Version 2.0 | First Created Oct 22, 2024 | Updated Nov 2, 2024

Keywords: Spatial Error, Spatial Lag, Geographically Weighted Regression, Global & Local Moran’s I, Akaiki Information Criterion, Schwarz Criterion, Log Likelihood, Likelihood Ratio Test

GitHub Repository: CPLN671-GW-Regression

Introduction

Philadelphia’s housing market has undergone significant transformations in recent years, with rising property values creating urgent concerns for urban planners, policymakers, and residents alike. This upward trend has intensified issues of housing affordability, disproportionately impacting low- and middle-income households. The rapid increase in housing values has spurred gentrification, displacing long-term residents and reshaping the socio-economic fabric of various neighborhoods across the city. As researchers have observed, gentrification often leads to social displacement, exacerbating inequality as housing affordability declines (Freeman & Braconi, 2004; Atkinson, 2004). Understanding the factors driving these shifts in property values is essential for addressing affordability challenges, promoting neighborhood stability, and fostering equitable development in Philadelphia (Lees, 2008).

In a previous study, Ordinary Least Squares (OLS) regression was employed to explore the relationships between median house values, the dependent variable, and several key socio-economic predictors. These predictors included educational attainment, vacancy rates, the proportion of detached single-family homes, and poverty levels. Each variable was chosen for its established influence on housing markets and its ability to shed light on underlying socio-economic conditions that may shape property values. For instance, educational attainment is positively associated with economic prosperity and housing demand, as areas with higher educational levels often benefit from higher incomes and greater investment Vacancy rates, on the other hand, are typically linked to neighborhood decline and reduced property values, as vacant properties signal economic distress, discourage investment, and may contribute to higher crime rates (Mallach, 2018). The housing market preference for single-family homes, which offer greater space and privacy, is well-documented in the literature (Glaeser & Gyourko, 2018), while research consistently demonstrates a negative correlation between poverty levels and housing values, with higher poverty rates often linked to decreased demand and underinvestment in local infrastructure (Galster, 2008).

Although OLS regression provides a foundational understanding of these relationships, it has limitations when applied to spatial data, as it assumes independence between observations and ignores potential spatial dependencies. Housing values in one area are often influenced by those in nearby areas, resulting in spatial autocorrelation that can lead to biased or misleading results when using traditional OLS methods. Spatial autocorrelation reflects Tobler’s First Law of Geography, which states that “everything is related to everything else, but near things are more related than distant things” (Tobler, 1970). When spatial dependencies are ignored, as is the case in OLS regression, the estimates may suffer from omitted variable bias, yielding inaccurate conclusions about the relationships between variables (Anselin, 1988).

To address these limitations, this report applies spatial econometric techniques, specifically spatial lag, spatial error, and geographically weighted regression (GWR) models, to more accurately capture the spatial dependencies affecting housing values in Philadelphia. The spatial lag model incorporates the influence of neighboring values directly into the regression, allowing for an understanding of how housing values in one area may affect those in adjacent areas (LeSage & Pace, 2009). The spatial error model accounts for spatial autocorrelation in the residuals, isolating unobserved spatially correlated factors that may influence housing values (Anselin, 1988). Lastly, the geographically weighted regression (GWR) model offers a localized perspective, allowing coefficients to vary by location and capturing the heterogeneity of relationships across different neighborhoods (Brunsdon, Fotheringham, & Charlton, 1996). By employing these spatial techniques, this study aims to enhance the accuracy of the initial OLS findings and provide a more comprehensive understanding of the socio-economic and spatial factors influencing housing values. These insights will support more effective policy interventions and urban development strategies aimed at achieving equitable and sustainable growth in Philadelphia.

Methods

Spatial Autocorrelation

The First Law of Geography, proposed by Waldo Tobler, states that “everything is related to everything else, but nearer things are more related than distant things.” This law captures the principle of spatial dependence, which underpins many spatial analyses, including spatial regression models. One way to measure spatial dependence is through Moran’s I, a statistic that quantifies spatial autocorrelation. Moran’s I for a variable is calculated as follows:

\[ I = \frac{n}{\sum_{i=1}^{n} \sum_{j=1}^{n} w_{ij}} \cdot \frac{\sum_{i=1}^{n} \sum_{j=1}^{n} w_{ij} (X_i - \bar{X})(X_j - \bar{X})}{\sum_{i=1}^{n} (X_i - \bar{X})^2} \] where \(n\) is the number of observations, \(X_i\) and \(X_j\) are the values of the variable at locations \(i\) and \(j\), respectively, \(\bar{X}\) is the mean of the variable, and \(w_{ij}\) is the spatial weight between locations \(i\) and \(j\).

Here, we use a spatial weight matrix constructed using a “Queen” contiguity method, which defines each unit’s neighbors based on shared boundaries or vertices. This matrix remains consistent across the analysis, although statisticians may use different weight matrices to assess model sensitivity to neighbor definitions.

Testing the significance of spatial autocorrelation involves evaluating whether the observed Moran’s I differs from what would be expected under spatial randomness. In hypothesis testing, the null hypothesis (\(H_0\)) is that there is no spatial autocorrelation, while the alternative (\(H_a\)) posits the presence of spatial autocorrelation. Using random permutations of data values across locations, we generate a reference distribution of Moran’s I under the null hypothesis and compare the observed statistic to this distribution.

Beyond global spatial autocorrelation measured by Moran’s I, local spatial autocorrelation identifies specific areas with clustering or dispersion. The significance of local Moran’s I is tested similarly using random permutations, and results can highlight statistically significant clusters or outliers that global measures might miss.

Ordinary Least Squares Regression

Ordinary Least Squares (OLS) regression is a statistical technique for estimating the relationship between a dependent variable and one or more independent variables by minimizing the squared differences between observed and predicted values. Key assumptions of OLS include linearity, independence of observations, homoscedasticity (constant error variance), normality of errors, and no multicollinearity among predictors.

In our first assignment, we used OLS regression to assess how vacancy rates, single-family housing percentage, educational attainment, and poverty levels influence median house value. All predictors were statistically significant, with vacancy rates and poverty levels negatively affecting house values, while single-family housing and educational attainment had positive effects. The model’s \(R^2\) was 0.66, explaining 66% of the variance in house values. However, some predictors exhibited non-linear patterns, and spatial autocorrelation suggested dependence among observations, indicating that future models could benefit from spatial regression techniques.

When data has a spatial component, the assumption that errors are random and independent often doesn’t hold, as nearby observations may exhibit similar error patterns. To test this, we can examine the spatial autocorrelation of the residuals using Moran’s I, which quantifies the degree of clustering in residuals. Another approach is to regress the residuals on nearby residuals from neighboring areas, such as block groups defined by the Queen matrix, to identify any spatial dependence. These tests help determine if spatial autocorrelation is present, indicating a need for spatial regression techniques.

In R, there are methods to test other key regression assumptions. For homoscedasticity (constant error variance), which is related to the independence of errors, we use the Breusch-Pagan Test, the Koenker-Bassett Test, and the White Test. The null hypothesis (\(H_0\)) is that errors are homoscedastic, while the alternative hypothesis (\(H_a\)) is that errors exhibit heteroscedasticity. For normality of errors, we can use the Jarque-Bera test. The null hypothesis is that residuals are normal, and the alternative hypothesis is that they are not normal. We want to not be able to reject the null hypothesis (i.e., get a p-value of 0.05 or higher).

Spatial Lag and Spatial Error Regression

In this report, we use R to run spatial lag and spatial error regressions. Among the two methods, spatial lag regression assumes the value of the dependent variable at one location is associated with the values of that variable in nearby locations, where nearby is as defined by the weights matrix W (rook, queen, within a certain distance of one another). In short, it introduces a spatially lagged dependent variable into the model, compared to our previous OLS regression. In our context, the spatial lag model could be represented as the following:

\[ \text{LNMEDHVAL} = \rho W \cdot \text{LNMEDHVAL} + \beta_0 + \beta_1 \cdot \text{PCTVACANT} + \beta_2 \cdot \text{PCTSINGLES} + \beta_3 \cdot \text{PCTBACHMOR} + \beta_4 \cdot \text{LNNBELPOV100} + \epsilon_i \]

where \(\text{LNMEDHVAL}\) is the log of median home value in location, \(\rho\) is the spatial lag coefficient that measures the influence of neighboring areas, \(W\) is the spatial weights matrix (in this case, the queenlist spatial weights), and \(W \cdot \text{LNMEDHVAL}\) is the spatially lagged dependent variable. The other terms are the same as in the OLS regression, where \(\text{PCTVACANT}\), \(\text{PCTSINGLES}\), \(\text{PCTBACHMOR}\), and \(\text{LNNBELPOV}\) are the predictors, \(\beta_1, \beta_2, \beta_3, \beta_4\) are the coefficients, \(\beta_0\) is the intercept term, and \(\epsilon_i\) is the error term.

The spatial error model, on the other hand, assumes that the error term is spatially autocorrelated, meaning that the residual in one location is associated with residuals at nearby locations, where nearby is also deifined by the weight matrix. The spatial error model could be represented as the following:

\[ \text{LNMEDHVAL} = \beta_0 + \beta_1 \cdot \text{PCTVACANT} + \beta_2 \cdot \text{PCTSINGLES} + \beta_3 \cdot \text{PCTBACHMOR} + \beta_4 \cdot \text{LNNBELPOV100} + \lambda W \cdot \epsilon + u \]

where \(\text{LNMEDHVAL}\) is the log of median home value, \(\beta_0\) is the intercept term, \(\text{PCTVACANT}\), \(\text{PCTSINGLES}\), \(\text{PCTBACHMOR}\), and \(\text{LNNBELPOV}\) are the predictors, \(\beta_1, \beta_2, \beta_3, \beta_4\) are the coefficients, as in OLS regression. \(\lambda\) is the spatial error coefficient that measures the degree of spatial correlation in the error term, \(W\) is the spatial weights matrix, \(W \cdot \epsilon\) is the spatially lagged error term, and \(u\) is the random noise. To put it simply, we are regressing residuals on the nearest neighbor residuals, thereby filtering the spatial information out of the OLS residuals

Spatial error regression and spatial lag regression both require the standard assumptions for OLS regression—such as linearity, homoscedasticity, and normality of errors—except for the assumption of spatial independence among observations. This adjustment allows the model to account for spatial structure in either the dependent variable (spatial lag) or the error term (spatial error). That said, their goal is to account for spatial dependence in the data, aiming to reduce spatial autocorrelation in the regression residuals. Both methods minimize spatial patterns in residuals that could otherwise lead to biased or inefficient estimates.

We compare the results of spatial lag and spatial error regression with OLS to decide whether the spatial models perform better than OLS based on a number of criteria: Akaike Information Criterion, Schwarz Criterion, Log Likelihood, and Likelihood Ratio Test. The Akaike Information Criterion (AIC) and Schwarz Criterion (SC or BIC) are used to compare the goodness of fit of different models. They are relative measures of the information that is lost when a given model is used to describe reality and can be said to describe the tradeoff between precision and complexity of the model. The lower the AIC or SC, the better the model.

The Log-Likelihood is associated with the maximum likelihood method of fitting a statistical model to the data and estimating model parameters. Maximum likelihood picks the values of the model parameters that make the data “more likely” than any other values of the parameters would make them. Higher log-likelihood values indicate a model that better explains the observed data.

The Likelihood Ratio Test is used to formally test whether adding spatial dependence to a model (as in spatial lag or spatial error models) significantly improves model fit compared to OLS. For this test, the null hypothesis (\(H_0\)) state that the spatial model does not provide a significantly better fit than OLS, while the alternative hypothesis (\(H_a\)) states that the spatial model provides a significantly better fit than OLS.

The decision rule is to reject the null hypothesis if the \(LR\) test statistic is significant (i.e., the p-value is below a chosen significance level, typically 0.05), and conclude that the spatial model is a better fit than OLS. If not, OLS may be adequate. It should be noted that the log likelihood method and the likelihood ratio test should be used for comparing nested models. Spatial lag and spatial error are not a special case of each other – we cannot use the log likelihood ratio to compare them.

Alternatively, we can also compare the spatial models to OLS using the Moran’s I statistic, which measures the spatial autocorrelation of the residuals. Moran’s I ranges from -1 to 1, where -1 indicates perfect dispersion, 0 indicates no spatial autocorrelation, and 1 indicates perfect correlation. For our models, the goal is to minimize spatial autocorrelation in the residuals. If the Moran’s I statistic for the residuals of a spatial lag or spatial error model is closer to zero than the Moran’s I for the OLS model, we can conclude that the spatial model better captures spatial dependencies.

Geographically Weighted Regression

We will conduct our Geographically Weighted Regression (GWR) analyses in R. GWR is a form of local regression that helps address spatial heterogeneity in data, which is essential when analyzing spatial data prone to Simpson’s Paradox — where a trend observed in aggregate data can differ from trends in subsets. GWR allows us to examine relationships at a local level rather than assuming they are uniform across the study area. The general GWR equation can be expressed as:

\[ y_i = \beta_{i0} + \sum_{k=1}^{m} \beta_{ik}x_{ik} + \epsilon_i \]

where: \(y_i\) is the dependent variable at location \(i\), \(\beta_{i0}\) is the intercept for location \(i\), allowing a unique baseline for each location, \(\beta_{ik}\) is the coefficient for the \(k\)-th predictor at location \(i\), \(x_{ik}\) is the value of the \(k\)-th predictor variable at location \(i\), and \(\epsilon_i\) is the error term at location \(i\).

In GWR, local regression is performed by fitting a regression model at each observation point, using a subset of neighboring points, with weights assigned based on their distance from the focal point. The concept of bandwidth controls the number of neighbors included, influencing how “local” each regression is. There are two types of bandwidths: adaptive and fixed. A fixed bandwidth uses a constant distance for all points, while an adaptive bandwidth varies, adjusting to include a set number of nearby observations regardless of spatial density. Here, we will use adaptive bandwidth, which is more appropriate as it accounts for varying spatial densities, providing a flexible analysis that better captures local relationships in areas with different population distributions.

Although GWR allows for spatial variation in relationships, the standard OLS assumptions (linearity, independence, homoscedasticity, and normality) still apply. Multicollinearity is assessed using the Condition Number, and high multicollinearity can cause issues in GWR, leading to unstable estimates and clustering in parameter estimates. It is also important to note that GWR does not provide p-values for coefficients, as the model focuses on exploring spatial patterns rather than testing global hypotheses.

Results

Global and Local Moran’s I

The Global Moran’s I analysis for the dependent variable, \(\text{LNMEDHVAL}\) (the natural log of median house value), reveals a pronounced level of spatial autocorrelation. With a Moran’s I statistic of 0.8, the results indicate a strong positive spatial autocorrelation. This high value suggests that areas with similar median house values tend to cluster geographically within the study area. In other words, neighborhoods with either high or low house values are more likely to be located near other neighborhoods with similar values, rather than being randomly distributed across space. This spatial clustering points to the presence of spatial dependencies in housing values, possibly driven by neighborhood characteristics, socio-economic factors, or other spatial processes influencing property values across the region.

To validate the significance of this observed spatial autocorrelation, a Monte Carlo permutation test was conducted using 1000 simulations. This approach involved randomly permuting the values of \(\text{LNMEDHVAL}\) across spatial units to generate a distribution of Moran’s I values under the null hypothesis of no spatial autocorrelation. The results, visualized in a histogram of permuted Moran’s I values, show that the observed Moran’s I of 0.8 lies at the extreme end of this distribution, marked in red. With an observed rank of 1000 (the highest rank in the distribution), the observed Moran’s I value exceeded all permuted values, emphasizing the extremity of the spatial clustering in the actual data.

The test result is further supported by a highly significant p-value (\(p < 2 \times 10^{-16}\)). This exceptionally low p-value strongly rejects the null hypothesis of no spatial autocorrelation, confirming that the spatial arrangement of \(\text{LNMEDHVAL}\) values is not random. Instead, the observed clustering is statistically significant, indicating that spatial processes are likely influencing the distribution of housing values in the study area.

globalmoranMC<-moran.mc(regData$LNMEDHVAL, queenlist, nsim=999, alternative="two.sided") 
globalmoranMC
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  regData$LNMEDHVAL 
## weights: queenlist  
## number of simulations + 1: 1000 
## 
## statistic = 0.8, observed rank = 1000, p-value <0.0000000000000002
## alternative hypothesis: two.sided

This graph shows the results of the Monte Carlo permutation test to assess the significance of the observed Moran’s I statistic.The histogram shows the frequency of Moran’s I values generated by these random permutations, with the observed Moran’s I value highlighted in red. The observed statistic of 0.8 stands far to the right of the permuted values, underscoring its extremity and significance. The high observed rank (1000) indicates that none of the permuted values exceeded the actual Moran’s I. This extremely low p-value provides strong evidence against the null hypothesis of no spatial autocorrelation, confirming that the spatial clustering observed in \(\text{LNMEDHVAL}\) is statistically significant and unlikely to be due to random variation.

ggplot(data.frame(res = globalmoranMC$res), aes(x = res)) +
  geom_histogram(bins = 100, fill = "#283d3b") +
  geom_vline(xintercept = globalmoranMC$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
  labs(title = "Observed and Permuted Global Moran's I",
       subtitle = "Observed Moran's I in Red",
       x = "Moran's I",
       y = "Count") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

This graph offers a different perspective on the spatial structure of \(\text{LNMEDHVAL}\) by displaying a scatter plot of the variable’s values against their spatial lag (a measure of neighboring values). The x-axis represents the logged median house values \(\text{LNMEDHVAL}\), while the y-axis displays the spatially lagged values of \(\text{LNMEDHVAL}\), computed based on a queen contiguity spatial weights matrix that considers neighboring spatial units. The positive slope of the red trend line in the scatter plot indicates a positive spatial autocorrelation, where areas with higher median house values are typically surrounded by other areas with high values, and similarly, areas with lower values are near other low-value areas. This linear relationship between a location’s \(\text{LNMEDHVAL}\) and the average values in surrounding locations highlights the clustering of similar values and supports the result from the Global Moran’s I statistic.

ggplot(data = data.frame(
  LNMEDHVAL = regData$LNMEDHVAL,
  spatial_lag = lag.listw(queenlist, regData$LNMEDHVAL)
), aes(x = LNMEDHVAL, y = spatial_lag)) +
  geom_point(color = "#283d3b", alpha = 0.7, size = 0.6) +  
  geom_smooth(method = "lm", color = "#c44536", se = FALSE) + 
  labs(title = "Global Moran's I Scatter Plot",
       x = "Logged Median House Value",
       y = "Spatial Lag of LNMEDHVAL") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

In a Local Moran’s I significance map, areas with significant low p-values refers to area where the spatial autocorrelation is statistically significant, either hotspots of concentrated high values or cold spots of low values. There areas are mostly found in the northwestern and central parts of the city. As we may see, these areas are then surrounded by areas with slightly higher p-values and then areas with even higher p-values, until p becomes insignificant.

moranSig.plot <- function(df, listw, title) {
  
  local <- localmoran(x = df$LNMEDHVAL, listw = listw, zero.policy = FALSE)
  
  df$Pr.z <- local[,  "Pr(z != E(Ii))"]  
  
  df$pval_category <- cut(df$Pr.z, 
                          breaks = c(0, 0.001, 0.01, 0.05, 1), 
                          labels = c("0.000 - 0.001", "0.001 - 0.010", "0.010 - 0.050", "0.050 - 1.000"), 
                          include.lowest = TRUE)
  
  if (!inherits(df, "sf")) {
    df <- st_as_sf(df)
  }
  
  ggplot(data = df) +
    geom_sf(aes(fill = pval_category), color = NA, alpha = 0.9) +
    scale_fill_brewer(type = "div", palette = 6, name = "P-Value") +
    labs(title = title) +
    theme(legend.text = element_text(size = 9),
        legend.title = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))
}

moranSig.plot(localmoran, queenlist, 'Significance Map of Local Moran I')

The Cluster Map derived from the Local Moran’s I analysis classified census tracts in Philadelphia into high-high, high-low, low-high, low-low, or not significant, representing different types of spatial relationships in house values within neighborhoods and their surroundings.

High-High Clusters: Areas classified as high-high are those where high values of median house prices are surrounded by other high-value areas. These clusters are prominently located in the northwestern parts of the city and some central regions, indicating pockets of economic affluence. The high concentration of high-value properties in these regions suggests established, affluent neighborhoods where housing prices remain high due to demand and possibly the presence of amenities or other attractive urban features.

Low-Low Clusters: Low-low clusters represent areas where low property values are surrounded by other low-value areas, highlighting economically disadvantaged zones. These clusters are predominantly found in the southwestern and northeastern parts of the city. The spatial clustering of low-value properties in these areas suggests neighborhoods that may face economic challenges, possibly with limited access to amenities or fewer investment opportunities. These regions may require targeted policy interventions to address underlying issues that contribute to the lower property values.

High-Low Clusters: High-low clusters are transitional zones where high-value areas are adjacent to lower-value areas. These areas, marked in light red on the map, are generally scattered around the boundaries of high-value neighborhoods, such as in sections of central and northwest Philadelphia. The proximity of high-value properties to lower-value ones in these clusters can indicate economic contrasts or areas experiencing gentrification, where property values in traditionally lower-income neighborhoods may be increasing due to spillover effects from nearby affluent areas.

Low-High Clusters: Low-high clusters, where low-value properties are surrounded by higher-value areas, are less common but appear in the northern and eastern parts of the city. These clusters suggest isolated pockets of economic disadvantage within more affluent areas. This pattern may indicate areas that are yet to benefit from surrounding economic growth or might be experiencing challenges that prevent them from aligning with the prosperity of neighboring regions.

Not Significant Areas: Lastly, the not significant areas, shaded in gray, indicate neighborhoods where the local Moran’s I statistic was not significant. These regions are scattered throughout the city, representing areas where house values do not exhibit strong spatial clustering. The lack of significant clustering in these areas suggests a more random distribution of house values, which may occur in more mixed-use or transitional neighborhoods where economic characteristics are varied.

hl.plot <- function(df, listw) {

  local <- localmoran(x = df$LNMEDHVAL, listw = listw, zero.policy = FALSE)
  quadrant <- vector(mode = 'numeric', length = nrow(df))  
  
  m.prop <- df$LNMEDHVAL - mean(df$LNMEDHVAL)
  m.local <- local[, 1] - mean(local[, 1])
  signif <- 0.05
  
  quadrant[m.prop > 0 & m.local > 0] <- 1  # high-high
  quadrant[m.prop < 0 & m.local < 0] <- 2  # low-low
  quadrant[m.prop < 0 & m.local > 0] <- 4  # low-high
  quadrant[m.prop > 0 & m.local < 0] <- 3  # high-low
  quadrant[local[, 5] > signif] <- 5  # insignificant
  
  df$quadrant <- factor(quadrant, levels = c(1, 3, 5, 2, 4), 
                        labels = c("High-High", "High-Low", "Non-Significant", "Low-Low", "Low-High"))
                          
  if (!inherits(df, "sf")) {
    df <- st_as_sf(df)
  }
  
  ggplot(data = df) +
    geom_sf(aes(fill = quadrant), color = "#848884", lwd = 0.07) +
    scale_fill_brewer(type = "div", palette = 6, name = "Cluster Type") + 
    labs(title = "Local Moran's I Cluster Map") +
    theme(legend.position="right",
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks =element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, linewidth=0.8)
        )
}

hl.plot(regData, queenlist)

OLS Regression Results

Below, we will provide a quick walk through of the OLS regression results. Detail interpretation and dicussion of the results can be found in the GitHub repository for assignment 1.

All predictors in our OLS regression, which include \(\text{PCTSINGLES}\), \(\text{PCTVACANT}\), \(\text{LNNBELPOV}\), and \(\text{PCTBACHMOR}\), are statistically significant in explaining \(\text{LNMEDHVAL}\). The model accounts for approximately 66.2% of the variance, as indicated by the R-squared value of 0.662.

OLS <- lm(LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + LNNBELPOV, data=regData)
fitted_values <- fitted(OLS)
residuals_values <- residuals(OLS)
standardized_residuals <- rstandard(OLS)
resnb<-sapply(queen, function(x) mean(standardized_residuals[x]))
regData <- regData %>%
  mutate(
    Fitted = fitted_values,
    Residuals = residuals_values,
    Standardized_Residuals = standardized_residuals,
    Residuals_NB = resnb)

summary(OLS)
## 
## Call:
## lm(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + 
##     LNNBELPOV, data = regData)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -2.2582 -0.2039  0.0382  0.2174  2.2434 
## 
## Coefficients:
##              Estimate Std. Error t value             Pr(>|t|)    
## (Intercept) 11.113778   0.046532  238.84 < 0.0000000000000002 ***
## PCTVACANT   -0.019156   0.000978  -19.59 < 0.0000000000000002 ***
## PCTSINGLES   0.002977   0.000703    4.23             0.000024 ***
## PCTBACHMOR   0.020910   0.000543   38.49 < 0.0000000000000002 ***
## LNNBELPOV   -0.078903   0.008457   -9.33 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.366 on 1715 degrees of freedom
## Multiple R-squared:  0.662,  Adjusted R-squared:  0.662 
## F-statistic:  841 on 4 and 1715 DF,  p-value: <0.0000000000000002

The results from the Breusch-Pagan, Koenker-Bassett, and White’s tests all detect heteroscedasticity in the model, as all p-values are extremely low. This confirms a clear violation of the homoscedasticity assumption in OLS regression.

# Breusch-Pagan Test
bptest(OLS, studentize=FALSE)
## 
##  Breusch-Pagan test
## 
## data:  OLS
## BP = 113, df = 4, p-value <0.0000000000000002
# Koenker-Bassett Test
bptest(OLS) 
## 
##  studentized Breusch-Pagan test
## 
## data:  OLS
## BP = 43, df = 4, p-value = 0.00000001
# White Test
white_test(OLS)
## White's test results
## 
## Null hypothesis: Homoskedasticity of the residuals
## Alternative hypothesis: Heteroskedasticity of the residuals
## Test Statistic: 43.94
## P-value: 0

Comparing to the scatter plot we made to identify heteroscedasticity from the previous assignment, the residuals in this scatter plot show no discernible trend of rising or falling variance with increasing fitted values; instead, they seem to be pretty uniformly distributed around the horizontal line at zero. Regardless, the Breusch-Pagan test is often more sensitive than a residual plot. Even small deviations that are hard to see visually may be detected.

ggplot(regData, aes(x = Fitted, y = Standardized_Residuals)) +
  geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +    
  geom_hline(yintercept = 0, linetype = "dashed", color = "#c44536", size = 1) +   #
  labs(
    title = "Scatter Plot of Standardized Residuals vs Fitted Values",
    x = "Fitted Values",
    y = "Standardized Residuals"
  ) +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

The results of the Jarque-Bera test indicate a significant deviation from normality in the residuals. The p-value is well below typical significance levels, and rejects the null hypothesis that the residuals are normally distributed. Therefore, the test results suggest that the residuals do not meet the normality assumption required for OLS regression.

# Jarque-Bera Test 
jarque.bera.test(OLS$residuals)
## 
##  Jarque Bera Test
## 
## data:  OLS$residuals
## X-squared = 779, df = 2, p-value <0.0000000000000002

Comparing to the histogram of standardized residuals from the previous assignment, we may also notice that the residuals are not perfectly normal. The histogram reveals a slight departure from a normal distribution and is left skewed. Despite that the skewness is not very pronounced, it is still consistent with the Jarque-Bera test results.

ggplot(regData, aes(x = Standardized_Residuals)) +
  geom_histogram(bins = 30, fill = "#283d3b", alpha = 0.9) +
  labs(title = "Histogram of Standardized Residuals", 
       x = "Standardized Residuals", 
       y = "Frequency") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

The scatterplot below shows the relationship between the standardized residuals of the OLS model and the residuals of their nearest neighbors. The upward-sloping trend line indicates a positive relationship between these residuals and their neighbors, suggesting spatial autocorrelation. The coefficient for the residuals of their nearest neighbors is 0.7323, with a highly significant p-value, demonstrating a strong positive relationship. This implies that residuals are positively correlated with those of their closest neighbors, implying spatial dependence.

ggplot(regData, aes(x = Residuals_NB, y = Standardized_Residuals)) +
  geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "#c44536", size = 1) +
  labs(title = "Residuals vs. Nearest Neighbor Residuals",
       x = "Nearest Neighbor Residuals",
       y = "Standardized Residuals") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

The Moran’s I scatterplot and the results from the permutations for OLS regression residuals both indicate significant spatial autocorrelation. The scatterplot shows a positive relationship between the logged median house values and their spatially lagged values, with a positive slope, confirming that high values tend to be near other high values, and low values cluster with other low values. The Moran’s I statistic from the Monte Carlo simulation is approximately 0.3, with an extremely low p-value, confirming that this spatial autocorrelation is statistically significant.

This significant spatial autocorrelation in the OLS residuals is problematic because it violates the OLS assumption of independent residuals. When residuals are spatially autocorrelated, it suggests that the model is missing spatial structure in the data, which could lead to biased or inefficient estimates.

OLS_moranMC<-moran.mc(standardized_residuals, queenlist, nsim=999, alternative="two.sided") 
OLS_moranMC
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  standardized_residuals 
## weights: queenlist  
## number of simulations + 1: 1000 
## 
## statistic = 0.3, observed rank = 1000, p-value <0.0000000000000002
## alternative hypothesis: two.sided

Both the Moran’s I statistic and the positive beta coefficient from the regression of standardized residuals on their nearest neighbors tell a similar story. They both reveal that spatial dependence is present in the residuals, suggesting that a spatial model, such as Geographically Weighted Regression (GWR) or a spatial autoregressive model, would be more appropriate for capturing the underlying spatial relationships in the data.

plt1 <- ggplot(data.frame(res = OLS_moranMC$res), aes(x = res)) +
  geom_histogram(bins = 100, fill = "#283d3b") +
  geom_vline(xintercept =OLS_moranMC$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
  labs(title = "Observed and Permuted Moran's I of OLS Residuals",
       subtitle = "Observed Moran's I in Red",
       x = "Moran's I",
       y = "Count") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt2 <- ggplot(data = data.frame(
  residuals =standardized_residuals,
  spatial_lag = lag.listw(queenlist, standardized_residuals)
), aes(x = residuals, y = spatial_lag)) +
  geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +  
  geom_smooth(method = "lm", color = "#c44536", se = FALSE) + 
  labs(title = "Moran's I Scatter Plot for OLS Residuals",
       x = "Logged Median House Value",
       y = "Spatial Lag of LNMEDHVAL") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt1 + plt2

Spatial Lag and Error Regression Results

Spatial Lag Regression

In the spatial lag regression output, we may see that the term \(\text{LNMEDHVAL}\), represented by \(\rho\) in the model, has an estimate of 0.651 and an extremely significant p-value (\(p < 2.22 \times 10^{-16}\)).This indicates that nearby values of the dependent value influence each other. The significant positive coefficient (\(\rho = 0.651\)) suggests a substantial positive spatial lag effect, meaning that higher median home values in neighboring areas are associated with higher median home values in the area being examined.

All predictors in the spatial lag model are significant. \(\text{PCTVACANT}\) has a coefficient of -0.0085 and is highly significant since \(p < 2.22 \times 10^{-16}\). It means a higher vacancy rate is associated with lower median home values. \(\text{PCTSINGLES}\) has a coefficient of 0.0020, significant with a \(p < 0.0001\). The positive association suggests that areas with a higher proportion of single households may slightly increase median home values. \(\text{PCTBACHMOR}\) has a coefficient of 0.0085 and is extremely significant (\(p < 2.22 \times 10^{-16}\)). Higher education levels are positively associated with home values, meaning that more educated areas tend to have higher home values. \(\text{LNNBELPOV}\) has a coefficient of -0.0341, also highly significant (\(p < 1 \times 10^{-7}\)). The negative association suggests that higher poverty levels are associated with lower median home values.

The OLS model also shows significant coefficients for all predictors, but with larger effect sizes. For example, has a coefficient of -0.0192 in OLS, compared to -0.0085 in spatial lag. This suggests that OLS overestimates the influence of these predictors due to omitted spatial dependence. For the other predictors, the OLS coefficients are also larger in magnitude than the spatial lag coefficients.

SL <- lagsarlm(LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + LNNBELPOV, data=regData, queenlist)
summary(SL)
## 
## Call:lagsarlm(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + 
##     LNNBELPOV, data = regData, listw = queenlist)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -1.655421 -0.117248  0.018654  0.133126  1.726436 
## 
## Type: lag 
## Coefficients: (asymptotic standard errors) 
##                Estimate  Std. Error  z value              Pr(>|z|)
## (Intercept)  3.89845489  0.20111357  19.3843 < 0.00000000000000022
## PCTVACANT   -0.00852940  0.00074367 -11.4694 < 0.00000000000000022
## PCTSINGLES   0.00203342  0.00051577   3.9425         0.00008063503
## PCTBACHMOR   0.00851381  0.00052193  16.3120 < 0.00000000000000022
## LNNBELPOV   -0.03405466  0.00629287  -5.4116         0.00000006246
## 
## Rho: 0.651, LR test value: 912, p-value: < 0.000000000000000222
## Asymptotic standard error: 0.018
##     z-value: 36.1, p-value: < 0.000000000000000222
## Wald statistic: 1301, p-value: < 0.000000000000000222
## 
## Log likelihood: -256 for lag model
## ML residual variance (sigma squared): 0.0719, (sigma: 0.268)
## Number of observations: 1720 
## Number of parameters estimated: 7 
## AIC: 525, (AIC for lm: 1435)
## LM test for residual autocorrelation
## test value: 67.7, p-value: 0.00000000000000022204

We ran Breusch-Pagan test to assess whether the residuals of the spatial lag regression model exhibit heteroscedasticity. As we may see, the test statistic for the spatial lag regression is \(BP = 211\) with \(df = 4\), and \(p < 2 \times 10^{-16}\). Given the extremely low p-value, we reject the null hypothesis of homoscedasticity, indicating that residuals in the spatial lag regression model remain heteroscedastic.

# Breusch-Pagan Test
bptest.Sarlm(SL, studentize=FALSE)
## 
##  Breusch-Pagan test
## 
## data:  
## BP = 211, df = 4, p-value <0.0000000000000002

When comparing the OLS and spatial lag regression models, several metrics show the spatial lag model provides a better fit. The spatial lag model has a significantly lower AIC (525) than OLS (1435), indicating a better model fit by penalizing less for added complexity. Similarly, the Schwarz Criterion is much lower for the spatial lag model, suggesting it captures the structure of the data more effectively than the OLS model. The spatial lag model (-256) has a higher log likelihood than OLS (-711), meaning that it better explains the variability in the data.

# Akaike Information Criterion
aic_ols <- AIC(OLS)
aic_sl <- AIC(SL)

# Schwarz Criterion
bic_ols <- BIC(OLS)
bic_sl <- BIC(SL)

# The Log Likelihood
loglik_ols <- logLik(OLS)
loglik_sl <- logLik(SL)

results <- data.frame(
  Model = c("OLS Regression", "Spatial Lag Regression"),
  AIC = c(aic_ols, aic_sl),
  SchwarzCriterion = c(bic_ols, bic_sl),
  LogLikelihood = c(loglik_ols, loglik_sl)
)

results %>%
  kable(row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) 
Model AIC SchwarzCriterion LogLikelihood
OLS Regression 1435 1468 -711
Spatial Lag Regression 525 564 -256

The Likelihood Ratio Test assesses the improvement in model fit between the OLS and spatial lag models, and the result we get here shows \(LR = 912\) with \(df = 1\), and \(p < 2 \times 10^{-16}\). With a large test statistic and low p-value, we conclude that the spatial lag model significantly improves fit over the OLS model.

# The Likelihood Ratio Test
lr_test <- LR.Sarlm(SL, OLS)
lr_test
## 
##  Likelihood ratio for spatial linear models
## 
## data:  
## Likelihood ratio = 912, df = 1, p-value <0.0000000000000002
## sample estimates:
##  Log likelihood of SL Log likelihood of OLS 
##                  -256                  -711

Finally, we examined Moran’s I for the spatial lag regression model’s residuals.The observed Moran’s I of -0.08 suggests a small negative spatial autocorrelation in the residuals of the spatial lag model. With \(p = 0.002\), we reject the null hypothesis of no spatial autocorrelation. This negative Moran’s I indicates that residuals are distributed with slight spatial dispersion rather than clustering, suggesting the spatial lag model effectively accounts for most spatial dependencies in the data.

SL_moranMc<-moran.mc(SL$residuals, queenlist,999, alternative="two.sided")
SL_moranMc
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  SL$residuals 
## weights: queenlist  
## number of simulations + 1: 1000 
## 
## statistic = -0.08, observed rank = 1, p-value = 0.002
## alternative hypothesis: two.sided

Both the residual histograms as well as the scatter plot support this conclusion. The histogram of residuals is also approximately normally distributed, and the scatter plot of residuals against fitted values shows no clear pattern or trend. All of these suggest that the spatial lag model is a good fit for the data compared to OLS.

plt3 <- ggplot(data.frame(res = SL$residuals), aes(x = res)) +
  geom_histogram(bins = 100, fill = "#283d3b") +
  geom_vline(xintercept =SL_moranMc$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
  labs(title = "Observed and Permuted Moran's I of SL Residuals",
       subtitle = "Observed Moran's I in Red",
       x = "Moran's I",
       y = "Count") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt4 <- ggplot(data = data.frame(
  residuals =SL$residuals,
  spatial_lag = lag.listw(queenlist, SL$residuals)
), aes(x = residuals, y = spatial_lag)) +
  geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +  
  geom_smooth(method = "lm", color = "#c44536", se = FALSE) + 
  labs(title = "Moran's I Scatter Plot for SL Residuals",
       x = "Logged Median House Value",
       y = "Spatial Lag of LNMEDHVAL") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt3 + plt4

Spatial Error Regression

In the spatial error regression model, the term \(\lambda\) represents the spatial autocorrelation within the model’s error terms. In this case, \(\lambda\) is estimated at 0.815 and is statistically significant, with \(p < 2.22 \times 10^{-16}\). This highly significant and large value of \(\lambda\) suggests a strong spatial dependency in the error terms.

Examining the individual predictors in the model, all variables are statistically significant at a high confidence level. \(\text{PCTVACANT}\) has an estimate of -0.0058 (\(p < 6.94 \times 10^{-9}\)), indicating that vacancy rates negatively affect median home values. \(\text{PCTSINGLES}\) has a positive coefficient of 0.0027 (\(p < 1.61 \times 10^{-5}\)), suggesting a small positive association with median home values. \(\text{PCTBACHMOR}\) , representing the percentage of bachelor’s degrees or higher, shows a positive effect with an estimate of 0.0098 (\(p < 2.20 \times 10^{-16}\)), indicating that higher education levels correlate with higher home values. \(\text{LNNBELPOV}\) has a negative estimate of -0.0345 and \(p < 1.11 \times 10^{-6}\), implying that higher levels of neighborhood poverty are associated with lower median home values.

Similar to spatial lag regression, when comparing these results with the OLS regression model, we observe that the coefficients for our predictors are all smaller in magnitude than their OLS counterparts. For instance, had a coefficient of -0.019156 in the OLS model, while in the spatial error model, it is reduced to -0.0058. This reduction in coefficient magnitude suggests that the spatial error model provides a more conservative estimate of the effects of these predictors on median home values, likely due to the accounted spatial autocorrelation.

SE <- errorsarlm(LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + LNNBELPOV, data=regData, queenlist)
summary(SE)
## 
## Call:errorsarlm(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + 
##     LNNBELPOV, data = regData, listw = queenlist)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -1.926477 -0.115408  0.014889  0.133852  1.948664 
## 
## Type: error 
## Coefficients: (asymptotic standard errors) 
##                Estimate  Std. Error  z value              Pr(>|z|)
## (Intercept) 10.90643427  0.05346777 203.9815 < 0.00000000000000022
## PCTVACANT   -0.00578308  0.00088670  -6.5220      0.00000000006937
## PCTSINGLES   0.00267792  0.00062083   4.3134      0.00001607389089
## PCTBACHMOR   0.00981293  0.00072896  13.4615 < 0.00000000000000022
## LNNBELPOV   -0.03453409  0.00708933  -4.8713      0.00000110881162
## 
## Lambda: 0.815, LR test value: 678, p-value: < 0.000000000000000222
## Asymptotic standard error: 0.0164
##     z-value: 49.8, p-value: < 0.000000000000000222
## Wald statistic: 2477, p-value: < 0.000000000000000222
## 
## Log likelihood: -373 for error model
## ML residual variance (sigma squared): 0.0766, (sigma: 0.277)
## Number of observations: 1720 
## Number of parameters estimated: 7 
## AIC: 759, (AIC for lm: 1435)

Based on the results of the Breusch-Pagan test, the spatial lag regression residuals are indeed heteroscedastic. The test statistic is \(BP = 23\) with \(df = 4\), and \(p < 0.0001\). Since the p-value is significantly lower than the conventional alpha levels (0.01, 0.05), we reject the null hypothesis of homoscedasticity. This indicates that the variance of the residuals is not constant across observations, suggesting the presence of heteroscedasticity in the model’s residuals.

# Breusch-Pagan Test 
bptest.Sarlm(SE, studentize=FALSE)
## 
##  Breusch-Pagan test
## 
## data:  
## BP = 23, df = 4, p-value = 0.0001

We also compared the spatial error model to the OLS model using the AIC, SC, log-likelihood, and likelihood ratio test. The spatial error model has a lower AIC (759) and SC (798) than the OLS model (1435 and 1468, respectively), indicating a better fit. The log-likelihood of the spatial error model (-373) is also higher than that of the OLS model (-711), suggesting that the spatial error model better explains the variability in the data.

# Akaike Information Criterion
aic_se <- AIC(SE)

# Schwarz Criterion
bic_se <- BIC(SE)

# The Log Likelihood
loglik_se <- logLik(SE)

results <- data.frame(
  Model = c("OLS Regression", "Spatial Lag Regression", "Spatial Error Regression"),
  AIC = c(aic_ols, aic_sl, aic_se),
  SchwarzCriterion = c(bic_ols, bic_sl, bic_se),
  LogLikelihood = c(loglik_ols, loglik_sl, loglik_se)
)

results %>%
  kable(row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) 
Model AIC SchwarzCriterion LogLikelihood
OLS Regression 1435 1468 -711
Spatial Lag Regression 525 564 -256
Spatial Error Regression 759 798 -373

According to the Likelihood Ratio Test, we see \(LR = 678\) with \(df = 1\), and \(p < 2 \times 10^{-16}\). With a large test statistic and low p-value, we may also conclude that the spatial error model significantly improves fit over the OLS model.

lr_test <- LR.Sarlm(SE, OLS)
lr_test
## 
##  Likelihood ratio for spatial linear models
## 
## data:  
## Likelihood ratio = 678, df = 1, p-value <0.0000000000000002
## sample estimates:
##  Log likelihood of SE Log likelihood of OLS 
##                  -373                  -711

Finally, we examined Moran’s I for the spatial error regression model’s residuals. The observed Moran’s I of -0.09 suggests a small negative spatial autocorrelation in the residuals of the spatial error model. With \(p = 0.002\), we reject the null hypothesis of no spatial autocorrelation. This negative Moran’s I indicates that residuals are distributed with slight spatial dispersion rather than clustering, suggesting the spatial error model effectively accounts for most spatial dependencies in the data.

SE_moranMc<-moran.mc(residuals(SE), queenlist,999, alternative="two.sided")
SE_moranMc
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  residuals(SE) 
## weights: queenlist  
## number of simulations + 1: 1000 
## 
## statistic = -0.09, observed rank = 1, p-value = 0.002
## alternative hypothesis: two.sided

Both the residual histograms as well as the scatter plot support this conclusion here again. The histogram of residuals is approximately normally distributed, and the scatter plot of residuals against fitted values shows a much less evident trend compared to the OLS model. Therefore, all of these suggest that the spatial error model is a good fit for the data compared to OLS.

plt5 <- ggplot(data.frame(res = residuals(SE)), aes(x = res)) +
  geom_histogram(bins = 100, fill = "#283d3b") +
  geom_vline(xintercept =SE_moranMc$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
  labs(title = "Observed and Permuted Moran's I of SE Residuals",
       subtitle = "Observed Moran's I in Red",
       x = "Moran's I",
       y = "Count") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt6 <- ggplot(data = data.frame(
  residuals = residuals(SE),
  spatial_lag = lag.listw(queenlist, residuals(SE))
), aes(x = residuals, y = spatial_lag)) +
  geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +  
  geom_smooth(method = "lm", color = "#c44536", se = FALSE) + 
  labs(title = "Moran's I Scatter Plot for SE Residuals",
       x = "Logged Median House Value",
       y = "Spatial Lag of LNMEDHVAL") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt5 + plt6

It should be noted that here, we also compared spatial lag model with the spatial error model. The spatial lag model has a lower AIC (525) and SC (564) than the spatial error model (759 and 798, respectively), indicating a better fit. The log-likelihood of the spatial lag model (-256) is also less negative than that of the spatial lag error (-373), suggesting that the spatial lag model better explains the variability in the data.

Geographically Weighted Regression Results

The \(R^2\) for the OLS regression model is 0.662, while the \(R^2\) (Quasi-global \(R^2\) ) for the GWR model is 0.848. The higher \(R^2\) value of the GWR model indicates that it does a better job of explaining the variance in the dependent variable \(\text{LNMEDHVAL}\) compared to the OLS model. This improvement suggests that the spatial variability captured by the GWR model provides a more accurate representation of the relationships between the predictors and the dependent variable, as GWR can account for spatial heterogeneity that OLS cannot.

Based on the Akaike Information Criterion (AIC) values, the GWR model, with an AIC of 309, demonstrates the best fit among the models compared. The Spatial Lag model has a higher AIC of 525, followed by the Spatial Error model at 759, and the OLS regression model at 1435. Since a lower AIC indicates a better fit, the GWR model appears to be the most effective in explaining the variance in the data. This suggests that GWR, which accounts for spatial heterogeneity by allowing model coefficients to vary across locations, provides a more accurate and robust fit for this dataset than the other models.

gwrmodel
## Call:
## gwr(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + 
##     LNNBELPOV, data = regDatashps, gweight = gwr.Gauss, adapt = bw, 
##     hatmatrix = TRUE, se.fit = TRUE)
## Kernel function: gwr.Gauss 
## Adaptive quantile: 0.00813 (about 13 of 1720 data points)
## Summary of GWR coefficient estimates at data points:
##                  Min.  1st Qu.   Median  3rd Qu.     Max. Global
## X.Intercept.  9.67276 10.71432 10.95424 11.17420 12.08314  11.11
## PCTVACANT    -0.03174 -0.01424 -0.00896 -0.00358  0.01679  -0.02
## PCTSINGLES   -0.02497 -0.00755 -0.00166  0.00423  0.01433   0.00
## PCTBACHMOR    0.00110  0.01014  0.01493  0.02022  0.03473   0.02
## LNNBELPOV    -0.23652 -0.07336 -0.04012 -0.01267  0.09488  -0.08
## Number of data points: 1720 
## Effective number of parameters (residual: 2traceS - traceS'S): 361 
## Effective degrees of freedom (residual: 2traceS - traceS'S): 1359 
## Sigma (residual: 2traceS - traceS'S): 0.276 
## Effective number of parameters (model: traceS): 258 
## Effective degrees of freedom (model: traceS): 1462 
## Sigma (model: traceS): 0.266 
## Sigma (ML): 0.246 
## AICc (GWR p. 61, eq 2.33; p. 96, eq. 4.21): 661 
## AIC (GWR p. 96, eq. 4.22): 309 
## Residual sum of squares: 104 
## Quasi-global R2: 0.848

The choropleth map of local \(R^2\) values from the GWR model illustrates how the model explains variations in logged median house values across the city. Darker-colored areas, such as the northwestern, parts of the northeastern, and far western regions, indicate a stronger model fit, where the predictors in the model explain a larger proportion of the variability in house values. In contrast, lighter-colored areas, particularly in the northern and western parts of the city, show a weaker model fit, suggesting that the predictors are less effective in capturing the variability in these regions.

gwrresults<-as.data.frame(gwrmodel$SDF)
regDatashps$localR2<-gwrresults$localR2
regDatashps_sf <- st_as_sf(regDatashps)
ggplot(data = regDatashps_sf) +
  geom_sf(aes(fill = localR2), color = NA) +  
  scale_fill_gradientn(colors = c("#FAF9F6", "#c44536"), 
                       name = "Local R-Squared", 
                       na.value = "transparent")+
  labs(title = "Local R-Squared from GWR", x = "", y = "") + 
   theme(legend.text = element_text(size = 9),
        legend.title = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))

The analysis indicates that the GWR model has successfully reduced spatial autocorrelation in the residuals compared to the OLS model. In the distribution of Moran’s I values for GWR residuals, the observed Moran’s I is close to zero, suggesting minimal spatial autocorrelation and aligning with the assumption of uncorrelated residuals. In contrast, the Moran’s I for the OLS residuals is both positive and statistically significant, indicating a stronger degree of spatial dependence.

The spatial lag model also reduces spatial autocorrelation in the residuals, although not as effectively as the GWR model. The spatial error model performs similarly, but the residuals exhibit slightly more spatial autocorrelation than those of the GWR model. Overall, these results suggest that the GWR model provides the best fit in terms of minimizing spatial autocorrelation, capturing local spatial variations more precisely than the spatial lag and spatial error models. This indicates that GWR is particularly effective for modeling spatial heterogeneity in this dataset.

GWR_moranMc<-moran.mc(gwrresults$gwr.e, queenlist, 999, alternative="two.sided")
GWR_moranMc
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  gwrresults$gwr.e 
## weights: queenlist  
## number of simulations + 1: 1000 
## 
## statistic = 0.03, observed rank = 992, p-value = 0.02
## alternative hypothesis: two.sided

The Moran’s I scatter plot for the GWR residuals shows minimal spatial autocorrelation, as indicated by the nearly horizontal trend of the line, suggesting that the GWR model has successfully addressed much of the spatial dependency present in the data. This is consistent with the earlier histogram results, where the Moran’s I value for GWR residuals was close to zero, further affirming that the model effectively captures local spatial variations in logged median house values.

plt7 <- ggplot(data.frame(res = gwrresults$gwr.e), aes(x = res)) +
  geom_histogram(bins = 100, fill = "#283d3b") +
  geom_vline(xintercept =GWR_moranMc$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
  labs(title = "Observed and Permuted Moran's I of GWR Residuals",
       subtitle = "Observed Moran's I in Red",
       x = "Moran's I",
       y = "Count") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt8 <- ggplot(data = data.frame(
  residuals = gwrresults$gwr.e,
  spatial_lag = lag.listw(queenlist, gwrresults$gwr.e)
), aes(x = residuals, y = spatial_lag)) +
  geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +  
  geom_smooth(method = "lm", color = "#c44536", se = FALSE) + 
  labs(title = "Moran's I Scatter Plot for GWR Residuals",
       x = "Logged Median House Value",
       y = "Spatial Lag of LNMEDHVAL") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"), 
        axis.text.x=element_text(size=6),
        axis.text.y=element_text(size=6), 
        axis.title=element_text(size=8))

plt7 + plt8

Looking at each predictors in detail, the vacancy rate generally has a negative impact on housing values, with significant negative effects observed in Center City, northwestern areas, parts of the northeastern region, and the western part of the city. However, there is a localized area in southern Center City where vacancy rates unexpectedly have a positive impact on housing values.

Single-family housing, in general, positively impacts housing values, particularly in the far northeast and far northwest areas, where this effect is more pronounced. Conversely, in some parts of the city—such as eastern Philadelphia, parts of the west, and sections of the south—the impact of single-family housing is negative and statistically significant.

The percentage of residents with a bachelor’s degree generally has a positive impact on housing values, with no areas showing a negative relationship across the city. This positive influence is especially statistically significant in the northern and northeastern parts of the city.

Finally, the poverty rate generally has a negative effect on housing values. This effect is more statistically significant in the southern, eastern, and northwestern parts of the city.

Overall, these spatial variations highlight how different factors affect housing values uniquely across Philadelphia, emphasizing the importance of localized analysis in understanding property dynamics.

regDatashps_sf$coefPCTVACANTst_cat <- cut(regDatashps_sf$coefPCTVACANTst, 
                                   breaks = c(-Inf, -2, 0, 2, Inf), 
                                   labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))
regDatashps_sf$coefPCTSINGLESst_cat <- cut(regDatashps_sf$coefPCTSINGLESst, 
                                   breaks = c(-Inf, -2, 0, 2, Inf), 
                                   labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))

regDatashps_sf$coefPCTBACHMORst_cat <- cut(regDatashps_sf$coefPCTBACHMORst,
                                   breaks = c(-Inf, -2, 0, 2, Inf), 
                                   labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))

regDatashps_sf$coefLNNBELPOVst_cat <- cut(regDatashps_sf$coefLNNBELPOVst,
                                   breaks = c(-Inf, -2, 0, 2, Inf), 
                                   labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))


p1 <- ggplot(regDatashps_sf) +
    geom_sf(aes(fill = coefPCTVACANTst_cat), color = NA) +  
    scale_fill_manual(
      values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"), 
      name = "Ratio Category"  
    ) +
   labs(title = "PCTVACANT Coefficient to Standard Error",
       x = "", y = "") +
   theme(legend.text = element_text(size = 9),
        legend.title = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))

p2 <- ggplot(regDatashps_sf) +
    geom_sf(aes(fill = coefPCTSINGLESst_cat), color = NA) +  
    scale_fill_manual(
      values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"), 
      name = "Ratio Category"  
    ) +
   labs(title = "PCTSINGLES Coefficient to Standard Error",
       x = "", y = "") +
   theme(legend.text = element_text(size = 9),
        legend.title = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))


p3 <- ggplot(regDatashps_sf) +
    geom_sf(aes(fill = coefPCTBACHMORst_cat), color = NA) +  
    scale_fill_manual(
      values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"), 
      name = "Ratio Category"  
    ) +
   labs(title = "PCTBACHMOR Coefficient to Standard Error",
       x = "", y = "") +
   theme(legend.text = element_text(size = 9),
        legend.title = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))

p4 <- ggplot(regDatashps_sf) +
    geom_sf(aes(fill = coefLNNBELPOVst_cat), color = NA) +  
    scale_fill_manual(
      values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"), 
      name = "Ratio Category"  
    ) +
   labs(title = "LNNBELPOV Coefficient to Standard Error",
       x = "", y = "") +
   theme(legend.text = element_text(size = 9),
        legend.title = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))

p1 + p2 + p3 + p4 + 
  plot_layout(ncol = 2)

Discussion

In this report, we conducted a comparative analysis of four regression methods—Ordinary Least Squares (OLS), Spatial Lag, Spatial Error, and Geographically Weighted Regression (GWR)—to evaluate their effectiveness in explaining the variance in the dependent variable, \(\text{LNMEDHVAL}\). Our findings indicate that the GWR model exhibited the highest explanatory power, with a quasi-global \(R^2\) of 0.84, compared to the OLS \(R^2\) of 0.662, suggesting that GWR is better suited to capture local variations in the data.

The Akaike Information Criterion (AIC) further supports the suitability of GWR, which achieved an AIC of 309, in contrast to the OLS AIC of 1435, the Spatial Lag AIC of 525, and the Spatial Error AIC of 759. Nevertheless, the lower AIC values in spatial lag and spatial error regression still indicate that both models provide are much better fit than the OLS model, especially the spatial lag model. Another observation is the reduction in the coefficient magnitudes for the predictors in the spatial lag and spatial error models compared to OLS, suggesting that they provide more conservative estimates of the predictors’ effects on median home values for accounting spatial autocorrelation. Yet, overall, our analysis demonstrates that the GWR method is the most effective for this dataset.

While GWR offers several advantages, such as capturing spatial heterogeneity and providing localized insights, it also has limitations, which is why a lot of spatial statisticians use it only for data exploration rather than for modeling. Most notably, a lot of assumptions we have in OLS still hold in GWR, such as linearity, homoscedasticity, and normality of errors. As an example, from our previous assignment, we know that there’s multicollinearity between predictors - higher education attainment is clearly associated with lower poverty level. As such, our current GWR model clearly does not account for that. We also know that some of our predictor variables, such as \(\text{PCTSINGLES}\) and \(\text{PCTBACHMOR}\) are not normally distributed, which violates the assumption.

Other than that, GWR requires at least 300 observations and user’s choice of bandwidth can significantly affect results. In our example we have way more than 300 observations and R automatically picked the bandwidths for us, still we should be cautious about the results.

We also need to be careful about the the use of term between spatially lagged residuals and spatial lag model residuals. The former term, spatially lagged residuals, refers to a series of residuals that take into account the influence of nearby observations through a weighting scheme. The latter term, spatial lag model residuals refers to the error terms from the result of a model that incorporates a spatial lag term (which is the values of the dependent variable from neighboring observations).

And lastly, we would like to highlight some limitations of using ArcGIS for GWR. The major issues is that ArcGIS does not always allow for the same level of flexibility in selecting bandwidth methods or kernel functions as R, and it has a very different and very confusing way of optimizing bandwidth. In addition, ArcGIS Pro does not give AIC, just AICc, which makes it difficult to compare GWR output to other models. More importantly, in the current and earlier versions of ArcGIS Pro, some local R-squares are negative, which is not possible in a regression model. Therefore, we recommend using R for GWR analysis to avoid these limitations and to have more control over the model selection process.

Reference

Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic Publishers.

Atkinson, R. (2004). The evidence on the impact of gentrification: New lessons for the urban renaissance? European Journal of Housing Policy, 4(1), 107–131. https://doi.org/10.1080/1461671042000215479

Brunsdon, C., Fotheringham, A. S., & Charlton, M. E. (1996). Geographically weighted regression: A method for exploring spatial nonstationarity. Geographical Analysis, 28(4), 281–298. https://doi.org/10.1111/j.1538-4632.1996.tb00936.x

Freeman, L., & Braconi, F. (2004). Gentrification and displacement. Journal of the American Planning Association, 70(1), 39–52. https://doi.org/10.1080/01944360408976337

Galster, G. C. (2008). Quantifying the effect of neighborhood land use and zoning on housing prices. Regional Science and Urban Economics, 38(3), 291–305. https://doi.org/10.1016/j.regsciurbeco.2008.03.003

Glaeser, E. L., & Gyourko, J. (2018). Rethinking federal housing policy: How to make housing plentiful and affordable. American Enterprise Institute.

Lees, L. (2008). Gentrification and social mixing: Towards an inclusive urban renaissance? Urban Studies, 45(12), 2449–2470. https://doi.org/10.1177/0042098008097099

LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. CRC Press.

Mallach, A. (2018). The divided city: Poverty and prosperity in urban America. Island Press. https://doi.org/10.5822/978-1-61091-781-0

Tobler, W. (1970). A computer movie simulating urban growth in the Detroit region. Economic Geography, 46, 234–240. https://doi.org/10.2307/143141

LS0tCnRpdGxlOiAiVXNpbmcgR2VvZ3JhcGhpY2FsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbiwgU3BhdGlhbCBMYWcsIGFuZCBTcGF0aWFsIEVycm9yIHRvIFByZWRpY3QgTWVkaWFuIEhvdXNlIFZhbHVlcyBpbiBQaGlsYWRlbHBoaWEiCmF1dGhvcjogIkVtaWx5IFpob3UsIFppeWkgR3VvLCBFbW1hIEppYW5nIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHNpbXBsZXgKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKCmVkaXRvcl9vcHRpb25zOgogIG1hcmtkb3duOgogICAgd3JhcDogc2VudGVuY2UKLS0tCgpWZXJzaW9uIDIuMCB8IEZpcnN0IENyZWF0ZWQgT2N0IDIyLCAyMDI0IHwgVXBkYXRlZCBOb3YgMiwgMjAyNAoKS2V5d29yZHM6IFNwYXRpYWwgRXJyb3IsIFNwYXRpYWwgTGFnLCBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uLCBHbG9iYWwgJiBMb2NhbCBNb3JhbidzIEksIEFrYWlraSBJbmZvcm1hdGlvbiBDcml0ZXJpb24sIFNjaHdhcnogQ3JpdGVyaW9uLCBMb2cgTGlrZWxpaG9vZCwgTGlrZWxpaG9vZCBSYXRpbyBUZXN0CgpHaXRIdWIgUmVwb3NpdG9yeTogW0NQTE42NzEtR1ctUmVncmVzc2lvbl0oaHR0cHM6Ly9naXRodWIuY29tL2VtaWx5emhvdTExMi9DUExONjcxLUdXLVJlZ3Jlc3Npb24pCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCgpgYGB7ciBsb2FkIHBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKb3B0aW9ucyhzY2lwZW49OTk5KQpvcHRpb25zKGRpZ2l0cyA9IDMpCgojIExpc3Qgb2YgcmVxdWlyZWQgcGFja2FnZXMKcGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwgInNmIiwgImhlcmUiLCAic3BkZXAiLCAic3Bnd3IiLCAic3BhdGlhbHJlZyIsIAogICAgICAgICAgICAgICJ3aGl0ZXN0cmFwIiwgImxtdGVzdCIsICJ0c2VyaWVzIiwgImdncGxvdDIiLCAia2FibGVFeHRyYSIsICJwYXRjaHdvcmsiKQoKIyBJbnN0YWxsIGFuZCBsb2FkIHJlcXVpcmVkIHBhY2thZ2VzCnBhY2thZ2UuY2hlY2sgPC0gbGFwcGx5KAogIHBhY2thZ2VzLAogIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSwgcXVpZXRseT1UUlVFKQogICAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKICAgIH0KICB9CikKCmBgYAoKCmBgYHtyIGxvYWQgZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCnJlZ0RhdGEgPC0gc3RfcmVhZChoZXJlKCJkYXRhIiwgIlJlZ3Jlc3Npb25EYXRhLnNocCIpKQoKYGBgCgojIEludHJvZHVjdGlvbgoKUGhpbGFkZWxwaGlhJ3MgaG91c2luZyBtYXJrZXQgaGFzIHVuZGVyZ29uZSBzaWduaWZpY2FudCB0cmFuc2Zvcm1hdGlvbnMgaW4gcmVjZW50IHllYXJzLCB3aXRoIHJpc2luZyBwcm9wZXJ0eSB2YWx1ZXMgY3JlYXRpbmcgdXJnZW50IGNvbmNlcm5zIGZvciB1cmJhbiBwbGFubmVycywgcG9saWN5bWFrZXJzLCBhbmQgcmVzaWRlbnRzIGFsaWtlLiBUaGlzIHVwd2FyZCB0cmVuZCBoYXMgaW50ZW5zaWZpZWQgaXNzdWVzIG9mIGhvdXNpbmcgYWZmb3JkYWJpbGl0eSwgZGlzcHJvcG9ydGlvbmF0ZWx5IGltcGFjdGluZyBsb3ctIGFuZCBtaWRkbGUtaW5jb21lIGhvdXNlaG9sZHMuIFRoZSByYXBpZCBpbmNyZWFzZSBpbiBob3VzaW5nIHZhbHVlcyBoYXMgc3B1cnJlZCBnZW50cmlmaWNhdGlvbiwgZGlzcGxhY2luZyBsb25nLXRlcm0gcmVzaWRlbnRzIGFuZCByZXNoYXBpbmcgdGhlIHNvY2lvLWVjb25vbWljIGZhYnJpYyBvZiB2YXJpb3VzIG5laWdoYm9yaG9vZHMgYWNyb3NzIHRoZSBjaXR5LiBBcyByZXNlYXJjaGVycyBoYXZlIG9ic2VydmVkLCBnZW50cmlmaWNhdGlvbiBvZnRlbiBsZWFkcyB0byBzb2NpYWwgZGlzcGxhY2VtZW50LCBleGFjZXJiYXRpbmcgaW5lcXVhbGl0eSBhcyBob3VzaW5nIGFmZm9yZGFiaWxpdHkgZGVjbGluZXMgKEZyZWVtYW4gJiBCcmFjb25pLCAyMDA0OyBBdGtpbnNvbiwgMjAwNCkuIFVuZGVyc3RhbmRpbmcgdGhlIGZhY3RvcnMgZHJpdmluZyB0aGVzZSBzaGlmdHMgaW4gcHJvcGVydHkgdmFsdWVzIGlzIGVzc2VudGlhbCBmb3IgYWRkcmVzc2luZyBhZmZvcmRhYmlsaXR5IGNoYWxsZW5nZXMsIHByb21vdGluZyBuZWlnaGJvcmhvb2Qgc3RhYmlsaXR5LCBhbmQgZm9zdGVyaW5nIGVxdWl0YWJsZSBkZXZlbG9wbWVudCBpbiBQaGlsYWRlbHBoaWEgKExlZXMsIDIwMDgpLgoKSW4gYSBwcmV2aW91cyBzdHVkeSwgT3JkaW5hcnkgTGVhc3QgU3F1YXJlcyAoT0xTKSByZWdyZXNzaW9uIHdhcyBlbXBsb3llZCB0byBleHBsb3JlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gbWVkaWFuIGhvdXNlIHZhbHVlcywgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgYW5kIHNldmVyYWwga2V5IHNvY2lvLWVjb25vbWljIHByZWRpY3RvcnMuIFRoZXNlIHByZWRpY3RvcnMgaW5jbHVkZWQgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgdmFjYW5jeSByYXRlcywgdGhlIHByb3BvcnRpb24gb2YgZGV0YWNoZWQgc2luZ2xlLWZhbWlseSBob21lcywgYW5kIHBvdmVydHkgbGV2ZWxzLiBFYWNoIHZhcmlhYmxlIHdhcyBjaG9zZW4gZm9yIGl0cyBlc3RhYmxpc2hlZCBpbmZsdWVuY2Ugb24gaG91c2luZyBtYXJrZXRzIGFuZCBpdHMgYWJpbGl0eSB0byBzaGVkIGxpZ2h0IG9uIHVuZGVybHlpbmcgc29jaW8tZWNvbm9taWMgY29uZGl0aW9ucyB0aGF0IG1heSBzaGFwZSBwcm9wZXJ0eSB2YWx1ZXMuIEZvciBpbnN0YW5jZSwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBpcyBwb3NpdGl2ZWx5IGFzc29jaWF0ZWQgd2l0aCBlY29ub21pYyBwcm9zcGVyaXR5IGFuZCBob3VzaW5nIGRlbWFuZCwgYXMgYXJlYXMgd2l0aCBoaWdoZXIgZWR1Y2F0aW9uYWwgbGV2ZWxzIG9mdGVuIGJlbmVmaXQgZnJvbSBoaWdoZXIgaW5jb21lcyBhbmQgZ3JlYXRlciBpbnZlc3RtZW50IFZhY2FuY3kgcmF0ZXMsIG9uIHRoZSBvdGhlciBoYW5kLCBhcmUgdHlwaWNhbGx5IGxpbmtlZCB0byBuZWlnaGJvcmhvb2QgZGVjbGluZSBhbmQgcmVkdWNlZCBwcm9wZXJ0eSB2YWx1ZXMsIGFzIHZhY2FudCBwcm9wZXJ0aWVzIHNpZ25hbCBlY29ub21pYyBkaXN0cmVzcywgZGlzY291cmFnZSBpbnZlc3RtZW50LCBhbmQgbWF5IGNvbnRyaWJ1dGUgdG8gaGlnaGVyIGNyaW1lIHJhdGVzIChNYWxsYWNoLCAyMDE4KS4gVGhlIGhvdXNpbmcgbWFya2V0IHByZWZlcmVuY2UgZm9yIHNpbmdsZS1mYW1pbHkgaG9tZXMsIHdoaWNoIG9mZmVyIGdyZWF0ZXIgc3BhY2UgYW5kIHByaXZhY3ksIGlzIHdlbGwtZG9jdW1lbnRlZCBpbiB0aGUgbGl0ZXJhdHVyZSAoR2xhZXNlciAmIEd5b3Vya28sIDIwMTgpLCB3aGlsZSByZXNlYXJjaCBjb25zaXN0ZW50bHkgZGVtb25zdHJhdGVzIGEgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBwb3ZlcnR5IGxldmVscyBhbmQgaG91c2luZyB2YWx1ZXMsIHdpdGggaGlnaGVyIHBvdmVydHkgcmF0ZXMgb2Z0ZW4gbGlua2VkIHRvIGRlY3JlYXNlZCBkZW1hbmQgYW5kIHVuZGVyaW52ZXN0bWVudCBpbiBsb2NhbCBpbmZyYXN0cnVjdHVyZSAoR2Fsc3RlciwgMjAwOCkuCgpBbHRob3VnaCBPTFMgcmVncmVzc2lvbiBwcm92aWRlcyBhIGZvdW5kYXRpb25hbCB1bmRlcnN0YW5kaW5nIG9mIHRoZXNlIHJlbGF0aW9uc2hpcHMsIGl0IGhhcyBsaW1pdGF0aW9ucyB3aGVuIGFwcGxpZWQgdG8gc3BhdGlhbCBkYXRhLCBhcyBpdCBhc3N1bWVzIGluZGVwZW5kZW5jZSBiZXR3ZWVuIG9ic2VydmF0aW9ucyBhbmQgaWdub3JlcyBwb3RlbnRpYWwgc3BhdGlhbCBkZXBlbmRlbmNpZXMuIEhvdXNpbmcgdmFsdWVzIGluIG9uZSBhcmVhIGFyZSBvZnRlbiBpbmZsdWVuY2VkIGJ5IHRob3NlIGluIG5lYXJieSBhcmVhcywgcmVzdWx0aW5nIGluIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIHRoYXQgY2FuIGxlYWQgdG8gYmlhc2VkIG9yIG1pc2xlYWRpbmcgcmVzdWx0cyB3aGVuIHVzaW5nIHRyYWRpdGlvbmFsIE9MUyBtZXRob2RzLiBTcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiByZWZsZWN0cyBUb2JsZXLigJlzIEZpcnN0IExhdyBvZiBHZW9ncmFwaHksIHdoaWNoIHN0YXRlcyB0aGF0IOKAnGV2ZXJ5dGhpbmcgaXMgcmVsYXRlZCB0byBldmVyeXRoaW5nIGVsc2UsIGJ1dCBuZWFyIHRoaW5ncyBhcmUgbW9yZSByZWxhdGVkIHRoYW4gZGlzdGFudCB0aGluZ3PigJ0gKFRvYmxlciwgMTk3MCkuIFdoZW4gc3BhdGlhbCBkZXBlbmRlbmNpZXMgYXJlIGlnbm9yZWQsIGFzIGlzIHRoZSBjYXNlIGluIE9MUyByZWdyZXNzaW9uLCB0aGUgZXN0aW1hdGVzIG1heSBzdWZmZXIgZnJvbSBvbWl0dGVkIHZhcmlhYmxlIGJpYXMsIHlpZWxkaW5nIGluYWNjdXJhdGUgY29uY2x1c2lvbnMgYWJvdXQgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgKEFuc2VsaW4sIDE5ODgpLgoKVG8gYWRkcmVzcyB0aGVzZSBsaW1pdGF0aW9ucywgdGhpcyByZXBvcnQgYXBwbGllcyBzcGF0aWFsIGVjb25vbWV0cmljIHRlY2huaXF1ZXMsIHNwZWNpZmljYWxseSBzcGF0aWFsIGxhZywgc3BhdGlhbCBlcnJvciwgYW5kIGdlb2dyYXBoaWNhbGx5IHdlaWdodGVkIHJlZ3Jlc3Npb24gKEdXUikgbW9kZWxzLCB0byBtb3JlIGFjY3VyYXRlbHkgY2FwdHVyZSB0aGUgc3BhdGlhbCBkZXBlbmRlbmNpZXMgYWZmZWN0aW5nIGhvdXNpbmcgdmFsdWVzIGluIFBoaWxhZGVscGhpYS4gVGhlIHNwYXRpYWwgbGFnIG1vZGVsIGluY29ycG9yYXRlcyB0aGUgaW5mbHVlbmNlIG9mIG5laWdoYm9yaW5nIHZhbHVlcyBkaXJlY3RseSBpbnRvIHRoZSByZWdyZXNzaW9uLCBhbGxvd2luZyBmb3IgYW4gdW5kZXJzdGFuZGluZyBvZiBob3cgaG91c2luZyB2YWx1ZXMgaW4gb25lIGFyZWEgbWF5IGFmZmVjdCB0aG9zZSBpbiBhZGphY2VudCBhcmVhcyAoTGVTYWdlICYgUGFjZSwgMjAwOSkuIFRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGFjY291bnRzIGZvciBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgcmVzaWR1YWxzLCBpc29sYXRpbmcgdW5vYnNlcnZlZCBzcGF0aWFsbHkgY29ycmVsYXRlZCBmYWN0b3JzIHRoYXQgbWF5IGluZmx1ZW5jZSBob3VzaW5nIHZhbHVlcyAoQW5zZWxpbiwgMTk4OCkuIExhc3RseSwgdGhlIGdlb2dyYXBoaWNhbGx5IHdlaWdodGVkIHJlZ3Jlc3Npb24gKEdXUikgbW9kZWwgb2ZmZXJzIGEgbG9jYWxpemVkIHBlcnNwZWN0aXZlLCBhbGxvd2luZyBjb2VmZmljaWVudHMgdG8gdmFyeSBieSBsb2NhdGlvbiBhbmQgY2FwdHVyaW5nIHRoZSBoZXRlcm9nZW5laXR5IG9mIHJlbGF0aW9uc2hpcHMgYWNyb3NzIGRpZmZlcmVudCBuZWlnaGJvcmhvb2RzIChCcnVuc2RvbiwgRm90aGVyaW5naGFtLCAmIENoYXJsdG9uLCAxOTk2KS4gQnkgZW1wbG95aW5nIHRoZXNlIHNwYXRpYWwgdGVjaG5pcXVlcywgdGhpcyBzdHVkeSBhaW1zIHRvIGVuaGFuY2UgdGhlIGFjY3VyYWN5IG9mIHRoZSBpbml0aWFsIE9MUyBmaW5kaW5ncyBhbmQgcHJvdmlkZSBhIG1vcmUgY29tcHJlaGVuc2l2ZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBzb2Npby1lY29ub21pYyBhbmQgc3BhdGlhbCBmYWN0b3JzIGluZmx1ZW5jaW5nIGhvdXNpbmcgdmFsdWVzLiBUaGVzZSBpbnNpZ2h0cyB3aWxsIHN1cHBvcnQgbW9yZSBlZmZlY3RpdmUgcG9saWN5IGludGVydmVudGlvbnMgYW5kIHVyYmFuIGRldmVsb3BtZW50IHN0cmF0ZWdpZXMgYWltZWQgYXQgYWNoaWV2aW5nIGVxdWl0YWJsZSBhbmQgc3VzdGFpbmFibGUgZ3Jvd3RoIGluIFBoaWxhZGVscGhpYS4KCiMgTWV0aG9kcyAKCiMjIFNwYXRpYWwgQXV0b2NvcnJlbGF0aW9uCgpUaGUgRmlyc3QgTGF3IG9mIEdlb2dyYXBoeSwgcHJvcG9zZWQgYnkgV2FsZG8gVG9ibGVyLCBzdGF0ZXMgdGhhdCAqImV2ZXJ5dGhpbmcgaXMgcmVsYXRlZCB0byBldmVyeXRoaW5nIGVsc2UsIGJ1dCBuZWFyZXIgdGhpbmdzIGFyZSBtb3JlIHJlbGF0ZWQgdGhhbiBkaXN0YW50IHRoaW5ncy4iKiBUaGlzIGxhdyBjYXB0dXJlcyB0aGUgcHJpbmNpcGxlIG9mIHNwYXRpYWwgZGVwZW5kZW5jZSwgd2hpY2ggdW5kZXJwaW5zIG1hbnkgc3BhdGlhbCBhbmFseXNlcywgaW5jbHVkaW5nIHNwYXRpYWwgcmVncmVzc2lvbiBtb2RlbHMuIE9uZSB3YXkgdG8gbWVhc3VyZSBzcGF0aWFsIGRlcGVuZGVuY2UgaXMgdGhyb3VnaCBNb3JhbidzIEksIGEgc3RhdGlzdGljIHRoYXQgcXVhbnRpZmllcyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gTW9yYW4ncyBJIGZvciBhIHZhcmlhYmxlIGlzIGNhbGN1bGF0ZWQgYXMgZm9sbG93czogCgoKJCQKSSA9IFxmcmFje259e1xzdW1fe2k9MX1ee259IFxzdW1fe2o9MX1ee259IHdfe2lqfX0gXGNkb3QgXGZyYWN7XHN1bV97aT0xfV57bn0gXHN1bV97aj0xfV57bn0gd197aWp9IChYX2kgLSBcYmFye1h9KShYX2ogLSBcYmFye1h9KX17XHN1bV97aT0xfV57bn0gKFhfaSAtIFxiYXJ7WH0pXjJ9CiQkCndoZXJlICRuJCBpcyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgJFhfaSQgYW5kICRYX2okIGFyZSB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSBhdCBsb2NhdGlvbnMgJGkkIGFuZCAkaiQsIHJlc3BlY3RpdmVseSwgJFxiYXJ7WH0kIGlzIHRoZSBtZWFuIG9mIHRoZSB2YXJpYWJsZSwgYW5kICR3X3tpan0kIGlzIHRoZSBzcGF0aWFsIHdlaWdodCBiZXR3ZWVuIGxvY2F0aW9ucyAkaSQgYW5kICRqJC4KCkhlcmUsIHdlIHVzZSBhIHNwYXRpYWwgd2VpZ2h0IG1hdHJpeCBjb25zdHJ1Y3RlZCB1c2luZyBhICJRdWVlbiIgY29udGlndWl0eSBtZXRob2QsIHdoaWNoIGRlZmluZXMgZWFjaCB1bml0J3MgbmVpZ2hib3JzIGJhc2VkIG9uIHNoYXJlZCBib3VuZGFyaWVzIG9yIHZlcnRpY2VzLiBUaGlzIG1hdHJpeCByZW1haW5zIGNvbnNpc3RlbnQgYWNyb3NzIHRoZSBhbmFseXNpcywgYWx0aG91Z2ggc3RhdGlzdGljaWFucyBtYXkgdXNlIGRpZmZlcmVudCB3ZWlnaHQgbWF0cmljZXMgdG8gYXNzZXNzIG1vZGVsIHNlbnNpdGl2aXR5IHRvIG5laWdoYm9yIGRlZmluaXRpb25zLgoKVGVzdGluZyB0aGUgc2lnbmlmaWNhbmNlIG9mIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGludm9sdmVzIGV2YWx1YXRpbmcgd2hldGhlciB0aGUgb2JzZXJ2ZWQgTW9yYW4ncyBJIGRpZmZlcnMgZnJvbSB3aGF0IHdvdWxkIGJlIGV4cGVjdGVkIHVuZGVyIHNwYXRpYWwgcmFuZG9tbmVzcy4gSW4gaHlwb3RoZXNpcyB0ZXN0aW5nLCB0aGUgbnVsbCBoeXBvdGhlc2lzIChcKCBIXzAgXCkpIGlzIHRoYXQgdGhlcmUgaXMgbm8gc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIHdoaWxlIHRoZSBhbHRlcm5hdGl2ZSAoXCggSF9hIFwpKSAgcG9zaXRzIHRoZSBwcmVzZW5jZSBvZiBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVXNpbmcgcmFuZG9tIHBlcm11dGF0aW9ucyBvZiBkYXRhIHZhbHVlcyBhY3Jvc3MgbG9jYXRpb25zLCB3ZSBnZW5lcmF0ZSBhIHJlZmVyZW5jZSBkaXN0cmlidXRpb24gb2YgTW9yYW4ncyBJIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgYW5kIGNvbXBhcmUgdGhlIG9ic2VydmVkIHN0YXRpc3RpYyB0byB0aGlzIGRpc3RyaWJ1dGlvbi4KCkJleW9uZCBnbG9iYWwgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gbWVhc3VyZWQgYnkgTW9yYW4ncyBJLCBsb2NhbCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpZGVudGlmaWVzIHNwZWNpZmljIGFyZWFzIHdpdGggY2x1c3RlcmluZyBvciBkaXNwZXJzaW9uLiBUaGUgc2lnbmlmaWNhbmNlIG9mIGxvY2FsIE1vcmFuJ3MgSSBpcyB0ZXN0ZWQgc2ltaWxhcmx5IHVzaW5nIHJhbmRvbSBwZXJtdXRhdGlvbnMsIGFuZCByZXN1bHRzIGNhbiBoaWdobGlnaHQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBjbHVzdGVycyBvciBvdXRsaWVycyB0aGF0IGdsb2JhbCBtZWFzdXJlcyBtaWdodCBtaXNzLgoKIyMgT3JkaW5hcnkgTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uCgpPcmRpbmFyeSBMZWFzdCBTcXVhcmVzIChPTFMpIHJlZ3Jlc3Npb24gaXMgYSBzdGF0aXN0aWNhbCB0ZWNobmlxdWUgZm9yIGVzdGltYXRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBvbmUgb3IgbW9yZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYnkgbWluaW1pemluZyB0aGUgc3F1YXJlZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIG9ic2VydmVkIGFuZCBwcmVkaWN0ZWQgdmFsdWVzLiBLZXkgYXNzdW1wdGlvbnMgb2YgT0xTIGluY2x1ZGUgbGluZWFyaXR5LCBpbmRlcGVuZGVuY2Ugb2Ygb2JzZXJ2YXRpb25zLCBob21vc2NlZGFzdGljaXR5IChjb25zdGFudCBlcnJvciB2YXJpYW5jZSksIG5vcm1hbGl0eSBvZiBlcnJvcnMsIGFuZCBubyBtdWx0aWNvbGxpbmVhcml0eSBhbW9uZyBwcmVkaWN0b3JzLgoKSW4gb3VyIGZpcnN0IGFzc2lnbm1lbnQsIHdlIHVzZWQgT0xTIHJlZ3Jlc3Npb24gdG8gYXNzZXNzIGhvdyB2YWNhbmN5IHJhdGVzLCBzaW5nbGUtZmFtaWx5IGhvdXNpbmcgcGVyY2VudGFnZSwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgYW5kIHBvdmVydHkgbGV2ZWxzIGluZmx1ZW5jZSBtZWRpYW4gaG91c2UgdmFsdWUuIEFsbCBwcmVkaWN0b3JzIHdlcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgd2l0aCB2YWNhbmN5IHJhdGVzIGFuZCBwb3ZlcnR5IGxldmVscyBuZWdhdGl2ZWx5IGFmZmVjdGluZyBob3VzZSB2YWx1ZXMsIHdoaWxlIHNpbmdsZS1mYW1pbHkgaG91c2luZyBhbmQgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBoYWQgcG9zaXRpdmUgZWZmZWN0cy4gVGhlIG1vZGVs4oCZcyBcKFJeMlwpIHdhcyAwLjY2LCBleHBsYWluaW5nIDY2JSBvZiB0aGUgdmFyaWFuY2UgaW4gaG91c2UgdmFsdWVzLiBIb3dldmVyLCBzb21lIHByZWRpY3RvcnMgZXhoaWJpdGVkIG5vbi1saW5lYXIgcGF0dGVybnMsIGFuZCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBzdWdnZXN0ZWQgZGVwZW5kZW5jZSBhbW9uZyBvYnNlcnZhdGlvbnMsIGluZGljYXRpbmcgdGhhdCBmdXR1cmUgbW9kZWxzIGNvdWxkIGJlbmVmaXQgZnJvbSBzcGF0aWFsIHJlZ3Jlc3Npb24gdGVjaG5pcXVlcy4KCldoZW4gZGF0YSBoYXMgYSBzcGF0aWFsIGNvbXBvbmVudCwgdGhlIGFzc3VtcHRpb24gdGhhdCBlcnJvcnMgYXJlIHJhbmRvbSBhbmQgaW5kZXBlbmRlbnQgb2Z0ZW4gZG9lc27igJl0IGhvbGQsIGFzIG5lYXJieSBvYnNlcnZhdGlvbnMgbWF5IGV4aGliaXQgc2ltaWxhciBlcnJvciBwYXR0ZXJucy4gVG8gdGVzdCB0aGlzLCB3ZSBjYW4gZXhhbWluZSB0aGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscyB1c2luZyBNb3JhbuKAmXMgSSwgd2hpY2ggcXVhbnRpZmllcyB0aGUgZGVncmVlIG9mIGNsdXN0ZXJpbmcgaW4gcmVzaWR1YWxzLiBBbm90aGVyIGFwcHJvYWNoIGlzIHRvIHJlZ3Jlc3MgdGhlIHJlc2lkdWFscyBvbiBuZWFyYnkgcmVzaWR1YWxzIGZyb20gbmVpZ2hib3JpbmcgYXJlYXMsIHN1Y2ggYXMgYmxvY2sgZ3JvdXBzIGRlZmluZWQgYnkgdGhlIFF1ZWVuIG1hdHJpeCwgdG8gaWRlbnRpZnkgYW55IHNwYXRpYWwgZGVwZW5kZW5jZS4gVGhlc2UgdGVzdHMgaGVscCBkZXRlcm1pbmUgaWYgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgcHJlc2VudCwgaW5kaWNhdGluZyBhIG5lZWQgZm9yIHNwYXRpYWwgcmVncmVzc2lvbiB0ZWNobmlxdWVzLgoKSW4gUiwgdGhlcmUgYXJlIG1ldGhvZHMgdG8gdGVzdCBvdGhlciBrZXkgcmVncmVzc2lvbiBhc3N1bXB0aW9ucy4gRm9yIGhvbW9zY2VkYXN0aWNpdHkgKGNvbnN0YW50IGVycm9yIHZhcmlhbmNlKSwgd2hpY2ggaXMgcmVsYXRlZCB0byB0aGUgaW5kZXBlbmRlbmNlIG9mIGVycm9ycywgd2UgdXNlIHRoZSAqKkJyZXVzY2gtUGFnYW4gVGVzdCoqLCB0aGUgKipLb2Vua2VyLUJhc3NldHQgVGVzdCoqLCBhbmQgdGhlICoqV2hpdGUgVGVzdCoqLiBUaGUgbnVsbCBoeXBvdGhlc2lzIChcKCBIXzAgXCkpIGlzIHRoYXQgZXJyb3JzIGFyZSBob21vc2NlZGFzdGljLCB3aGlsZSB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyAoXCggSF9hIFwpKSBpcyB0aGF0IGVycm9ycyBleGhpYml0IGhldGVyb3NjZWRhc3RpY2l0eS4gRm9yIG5vcm1hbGl0eSBvZiBlcnJvcnMsIHdlIGNhbiB1c2UgdGhlICoqSmFycXVlLUJlcmEgdGVzdCoqLiBUaGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgcmVzaWR1YWxzIGFyZSBub3JtYWwsIGFuZCB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZXkgYXJlIG5vdCBub3JtYWwuIFdlIHdhbnQgdG8gbm90IGJlIGFibGUgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgKGkuZS4sIGdldCBhIHAtdmFsdWUgb2YgMC4wNSBvciBoaWdoZXIpLgoKCiMjIFNwYXRpYWwgTGFnIGFuZCBTcGF0aWFsIEVycm9yIFJlZ3Jlc3Npb24KCkluIHRoaXMgcmVwb3J0LCB3ZSB1c2UgUiB0byBydW4gc3BhdGlhbCBsYWcgYW5kIHNwYXRpYWwgZXJyb3IgcmVncmVzc2lvbnMuIEFtb25nIHRoZSB0d28gbWV0aG9kcywgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBhc3N1bWVzIHRoZSB2YWx1ZSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGF0IG9uZSBsb2NhdGlvbiBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIHZhbHVlcyBvZiB0aGF0IHZhcmlhYmxlIGluIG5lYXJieSBsb2NhdGlvbnMsIHdoZXJlIG5lYXJieSBpcyBhcyBkZWZpbmVkIGJ5IHRoZSB3ZWlnaHRzIG1hdHJpeCBXIChyb29rLCBxdWVlbiwgd2l0aGluIGEgY2VydGFpbiBkaXN0YW5jZSBvZiBvbmUgYW5vdGhlcikuIEluIHNob3J0LCBpdCBpbnRyb2R1Y2VzIGEgc3BhdGlhbGx5IGxhZ2dlZCBkZXBlbmRlbnQgdmFyaWFibGUgaW50byB0aGUgbW9kZWwsIGNvbXBhcmVkIHRvIG91ciBwcmV2aW91cyBPTFMgcmVncmVzc2lvbi4gSW4gb3VyIGNvbnRleHQsIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBjb3VsZCBiZSByZXByZXNlbnRlZCBhcyB0aGUgZm9sbG93aW5nOiAKCiQkClx0ZXh0e0xOTUVESFZBTH0gPSBccmhvIFcgXGNkb3QgXHRleHR7TE5NRURIVkFMfSArIFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IFx0ZXh0e1BDVFZBQ0FOVH0gKyBcYmV0YV8yIFxjZG90IFx0ZXh0e1BDVFNJTkdMRVN9ICsgXGJldGFfMyBcY2RvdCBcdGV4dHtQQ1RCQUNITU9SfSArIFxiZXRhXzQgXGNkb3QgXHRleHR7TE5OQkVMUE9WMTAwfSArIFxlcHNpbG9uX2kKJCQKCndoZXJlIFwoXHRleHR7TE5NRURIVkFMfVwpIGlzIHRoZSBsb2cgb2YgbWVkaWFuIGhvbWUgdmFsdWUgaW4gbG9jYXRpb24sIFwoIFxyaG8gXCkgaXMgdGhlIHNwYXRpYWwgbGFnIGNvZWZmaWNpZW50IHRoYXQgbWVhc3VyZXMgdGhlIGluZmx1ZW5jZSBvZiBuZWlnaGJvcmluZyBhcmVhcywgXCggVyBcKSBpcyB0aGUgc3BhdGlhbCB3ZWlnaHRzIG1hdHJpeCAoaW4gdGhpcyBjYXNlLCB0aGUgcXVlZW5saXN0IHNwYXRpYWwgd2VpZ2h0cyksIGFuZCBcKCBXIFxjZG90IFx0ZXh0e0xOTUVESFZBTH0gXCkgaXMgdGhlIHNwYXRpYWxseSBsYWdnZWQgZGVwZW5kZW50IHZhcmlhYmxlLiBUaGUgb3RoZXIgdGVybXMgYXJlIHRoZSBzYW1lIGFzIGluIHRoZSBPTFMgcmVncmVzc2lvbiwgd2hlcmUgXChcdGV4dHtQQ1RWQUNBTlR9XCksIFwoXHRleHR7UENUU0lOR0xFU31cKSwgXChcdGV4dHtQQ1RCQUNITU9SfVwpLCBhbmQgXChcdGV4dHtMTk5CRUxQT1Z9XCkgYXJlIHRoZSBwcmVkaWN0b3JzLCBcKCBcYmV0YV8xLCBcYmV0YV8yLCBcYmV0YV8zLCBcYmV0YV80IFwpIGFyZSB0aGUgY29lZmZpY2llbnRzLCBcKCBcYmV0YV8wIFwpIGlzIHRoZSBpbnRlcmNlcHQgdGVybSwgYW5kIFwoIFxlcHNpbG9uX2kgXCkgaXMgdGhlIGVycm9yIHRlcm0uCgpUaGUgc3BhdGlhbCBlcnJvciBtb2RlbCwgb24gdGhlIG90aGVyIGhhbmQsIGFzc3VtZXMgdGhhdCB0aGUgZXJyb3IgdGVybSBpcyBzcGF0aWFsbHkgYXV0b2NvcnJlbGF0ZWQsIG1lYW5pbmcgdGhhdCB0aGUgcmVzaWR1YWwgaW4gb25lIGxvY2F0aW9uIGlzIGFzc29jaWF0ZWQgd2l0aCByZXNpZHVhbHMgYXQgbmVhcmJ5IGxvY2F0aW9ucywgd2hlcmUgbmVhcmJ5IGlzIGFsc28gZGVpZmluZWQgYnkgdGhlIHdlaWdodCBtYXRyaXguIFRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGNvdWxkIGJlIHJlcHJlc2VudGVkIGFzIHRoZSBmb2xsb3dpbmc6CgokJApcdGV4dHtMTk1FREhWQUx9ID0gXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgXHRleHR7UENUVkFDQU5UfSArIFxiZXRhXzIgXGNkb3QgXHRleHR7UENUU0lOR0xFU30gKyBcYmV0YV8zIFxjZG90IFx0ZXh0e1BDVEJBQ0hNT1J9ICsgXGJldGFfNCBcY2RvdCBcdGV4dHtMTk5CRUxQT1YxMDB9ICsgXGxhbWJkYSBXIFxjZG90IFxlcHNpbG9uICsgdQokJAoKd2hlcmUgXChcdGV4dHtMTk1FREhWQUx9XCkgaXMgdGhlIGxvZyBvZiBtZWRpYW4gaG9tZSB2YWx1ZSwgXCggXGJldGFfMCBcKSBpcyB0aGUgaW50ZXJjZXB0IHRlcm0sIFwoXHRleHR7UENUVkFDQU5UfVwpLCBcKFx0ZXh0e1BDVFNJTkdMRVN9XCksIFwoXHRleHR7UENUQkFDSE1PUn1cKSwgYW5kIFwoXHRleHR7TE5OQkVMUE9WfVwpIGFyZSB0aGUgcHJlZGljdG9ycywgXCggXGJldGFfMSwgXGJldGFfMiwgXGJldGFfMywgXGJldGFfNCBcKSBhcmUgdGhlIGNvZWZmaWNpZW50cywgYXMgaW4gT0xTIHJlZ3Jlc3Npb24uIFwoIFxsYW1iZGEgXCkgaXMgdGhlIHNwYXRpYWwgZXJyb3IgY29lZmZpY2llbnQgdGhhdCBtZWFzdXJlcyB0aGUgZGVncmVlIG9mIHNwYXRpYWwgY29ycmVsYXRpb24gaW4gdGhlIGVycm9yIHRlcm0sIFwoIFcgXCkgaXMgdGhlIHNwYXRpYWwgd2VpZ2h0cyBtYXRyaXgsIFwoIFcgXGNkb3QgXGVwc2lsb24gXCkgaXMgdGhlIHNwYXRpYWxseSBsYWdnZWQgZXJyb3IgdGVybSwgYW5kIFwoIHUgXCkgaXMgdGhlIHJhbmRvbSBub2lzZS4gVG8gcHV0IGl0IHNpbXBseSwgd2UgYXJlIHJlZ3Jlc3NpbmcgcmVzaWR1YWxzIG9uIHRoZSBuZWFyZXN0IG5laWdoYm9yIHJlc2lkdWFscywgdGhlcmVieSBmaWx0ZXJpbmcgdGhlIHNwYXRpYWwgaW5mb3JtYXRpb24gb3V0IG9mIHRoZSBPTFMgcmVzaWR1YWxzCgpTcGF0aWFsIGVycm9yIHJlZ3Jlc3Npb24gYW5kIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24gYm90aCByZXF1aXJlIHRoZSBzdGFuZGFyZCBhc3N1bXB0aW9ucyBmb3IgT0xTIHJlZ3Jlc3Npb27igJRzdWNoIGFzIGxpbmVhcml0eSwgaG9tb3NjZWRhc3RpY2l0eSwgYW5kIG5vcm1hbGl0eSBvZiBlcnJvcnPigJRleGNlcHQgZm9yIHRoZSBhc3N1bXB0aW9uIG9mIHNwYXRpYWwgaW5kZXBlbmRlbmNlIGFtb25nIG9ic2VydmF0aW9ucy4gVGhpcyBhZGp1c3RtZW50IGFsbG93cyB0aGUgbW9kZWwgdG8gYWNjb3VudCBmb3Igc3BhdGlhbCBzdHJ1Y3R1cmUgaW4gZWl0aGVyIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKHNwYXRpYWwgbGFnKSBvciB0aGUgZXJyb3IgdGVybSAoc3BhdGlhbCBlcnJvcikuIFRoYXQgc2FpZCwgdGhlaXIgZ29hbCBpcyB0byBhY2NvdW50IGZvciBzcGF0aWFsIGRlcGVuZGVuY2UgaW4gdGhlIGRhdGEsIGFpbWluZyB0byByZWR1Y2Ugc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlZ3Jlc3Npb24gcmVzaWR1YWxzLiBCb3RoIG1ldGhvZHMgbWluaW1pemUgc3BhdGlhbCBwYXR0ZXJucyBpbiByZXNpZHVhbHMgdGhhdCBjb3VsZCBvdGhlcndpc2UgbGVhZCB0byBiaWFzZWQgb3IgaW5lZmZpY2llbnQgZXN0aW1hdGVzLgoKV2UgY29tcGFyZSB0aGUgcmVzdWx0cyBvZiBzcGF0aWFsIGxhZyBhbmQgc3BhdGlhbCBlcnJvciByZWdyZXNzaW9uIHdpdGggT0xTIHRvIGRlY2lkZSB3aGV0aGVyIHRoZSBzcGF0aWFsIG1vZGVscyBwZXJmb3JtIGJldHRlciB0aGFuIE9MUyBiYXNlZCBvbiBhIG51bWJlciBvZiBjcml0ZXJpYTogQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbiwgU2Nod2FyeiBDcml0ZXJpb24sIExvZyBMaWtlbGlob29kLCBhbmQgTGlrZWxpaG9vZCBSYXRpbyBUZXN0LiBUaGUgKipBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpKiogYW5kICoqU2Nod2FyeiBDcml0ZXJpb24gKFNDIG9yIEJJQykqKiBhcmUgdXNlZCB0byBjb21wYXJlIHRoZSBnb29kbmVzcyBvZiBmaXQgb2YgZGlmZmVyZW50IG1vZGVscy4gVGhleSBhcmUgcmVsYXRpdmUgbWVhc3VyZXMgb2YgdGhlIGluZm9ybWF0aW9uIHRoYXQgaXMgbG9zdCB3aGVuIGEgZ2l2ZW4gbW9kZWwgaXMgdXNlZCB0byBkZXNjcmliZSByZWFsaXR5IGFuZCBjYW4gYmUgc2FpZCB0byBkZXNjcmliZSB0aGUgdHJhZGVvZmYgYmV0d2VlbiBwcmVjaXNpb24gYW5kIGNvbXBsZXhpdHkgb2YgdGhlIG1vZGVsLiBUaGUgbG93ZXIgdGhlIEFJQyBvciBTQywgdGhlIGJldHRlciB0aGUgbW9kZWwuCgpUaGUgKipMb2ctTGlrZWxpaG9vZCoqIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgbWF4aW11bSBsaWtlbGlob29kIG1ldGhvZCBvZiBmaXR0aW5nIGEgc3RhdGlzdGljYWwgbW9kZWwgdG8gdGhlIGRhdGEgYW5kIGVzdGltYXRpbmcgbW9kZWwgcGFyYW1ldGVycy4gTWF4aW11bSBsaWtlbGlob29kIHBpY2tzIHRoZSB2YWx1ZXMgb2YgdGhlIG1vZGVsIHBhcmFtZXRlcnMgdGhhdCBtYWtlIHRoZSBkYXRhICJtb3JlIGxpa2VseSIgdGhhbiBhbnkgb3RoZXIgdmFsdWVzIG9mIHRoZSBwYXJhbWV0ZXJzIHdvdWxkIG1ha2UgdGhlbS4gIEhpZ2hlciBsb2ctbGlrZWxpaG9vZCB2YWx1ZXMgaW5kaWNhdGUgYSBtb2RlbCB0aGF0IGJldHRlciBleHBsYWlucyB0aGUgb2JzZXJ2ZWQgZGF0YS4gCgpUaGUgKipMaWtlbGlob29kIFJhdGlvIFRlc3QqKiBpcyB1c2VkIHRvIGZvcm1hbGx5IHRlc3Qgd2hldGhlciBhZGRpbmcgc3BhdGlhbCBkZXBlbmRlbmNlIHRvIGEgbW9kZWwgKGFzIGluIHNwYXRpYWwgbGFnIG9yIHNwYXRpYWwgZXJyb3IgbW9kZWxzKSBzaWduaWZpY2FudGx5IGltcHJvdmVzIG1vZGVsIGZpdCBjb21wYXJlZCB0byBPTFMuIEZvciB0aGlzIHRlc3QsIHRoZSBudWxsIGh5cG90aGVzaXMgKFwoIEhfMCBcKSkgc3RhdGUgdGhhdCB0aGUgc3BhdGlhbCBtb2RlbCBkb2VzIG5vdCBwcm92aWRlIGEgc2lnbmlmaWNhbnRseSBiZXR0ZXIgZml0IHRoYW4gT0xTLCB3aGlsZSB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyAoXCggSF9hIFwpKSBzdGF0ZXMgdGhhdCB0aGUgc3BhdGlhbCBtb2RlbCBwcm92aWRlcyBhIHNpZ25pZmljYW50bHkgYmV0dGVyIGZpdCB0aGFuIE9MUy4gCgpUaGUgZGVjaXNpb24gcnVsZSBpcyB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpZiB0aGUgXCggTFIgXCkgdGVzdCBzdGF0aXN0aWMgaXMgc2lnbmlmaWNhbnQgKGkuZS4sIHRoZSBwLXZhbHVlIGlzIGJlbG93IGEgY2hvc2VuIHNpZ25pZmljYW5jZSBsZXZlbCwgdHlwaWNhbGx5IDAuMDUpLCBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgc3BhdGlhbCBtb2RlbCBpcyBhIGJldHRlciBmaXQgdGhhbiBPTFMuIElmIG5vdCwgT0xTIG1heSBiZSBhZGVxdWF0ZS4gKkl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoZSBsb2cgbGlrZWxpaG9vZCBtZXRob2QgYW5kIHRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3Qgc2hvdWxkIGJlIHVzZWQgZm9yIGNvbXBhcmluZyBuZXN0ZWQgbW9kZWxzLiBTcGF0aWFsIGxhZyBhbmQgc3BhdGlhbCBlcnJvciBhcmUgbm90IGEgc3BlY2lhbCBjYXNlIG9mIGVhY2ggb3RoZXIg4oCTIHdlIGNhbm5vdCB1c2UgdGhlIGxvZyBsaWtlbGlob29kIHJhdGlvIHRvIGNvbXBhcmUgdGhlbS4qCgpBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gYWxzbyBjb21wYXJlIHRoZSBzcGF0aWFsIG1vZGVscyB0byBPTFMgdXNpbmcgdGhlICoqTW9yYW4ncyBJKiogc3RhdGlzdGljLCB3aGljaCBtZWFzdXJlcyB0aGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscy4gTW9yYW4ncyBJIHJhbmdlcyBmcm9tIC0xIHRvIDEsIHdoZXJlIC0xIGluZGljYXRlcyBwZXJmZWN0IGRpc3BlcnNpb24sIDAgaW5kaWNhdGVzIG5vIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLCBhbmQgMSBpbmRpY2F0ZXMgcGVyZmVjdCBjb3JyZWxhdGlvbi4gRm9yIG91ciBtb2RlbHMsIHRoZSBnb2FsIGlzIHRvIG1pbmltaXplIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMuICBJZiB0aGUgTW9yYW7igJlzIEkgc3RhdGlzdGljIGZvciB0aGUgcmVzaWR1YWxzIG9mIGEgc3BhdGlhbCBsYWcgb3Igc3BhdGlhbCBlcnJvciBtb2RlbCBpcyBjbG9zZXIgdG8gemVybyB0aGFuIHRoZSBNb3JhbuKAmXMgSSBmb3IgdGhlIE9MUyBtb2RlbCwgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlIHNwYXRpYWwgbW9kZWwgYmV0dGVyIGNhcHR1cmVzIHNwYXRpYWwgZGVwZW5kZW5jaWVzLiAKCgojIyBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uCgpXZSB3aWxsIGNvbmR1Y3Qgb3VyIEdlb2dyYXBoaWNhbGx5IFdlaWdodGVkIFJlZ3Jlc3Npb24gKEdXUikgYW5hbHlzZXMgaW4gUi4gR1dSIGlzIGEgZm9ybSBvZiBsb2NhbCByZWdyZXNzaW9uIHRoYXQgaGVscHMgYWRkcmVzcyBzcGF0aWFsIGhldGVyb2dlbmVpdHkgaW4gZGF0YSwgd2hpY2ggaXMgZXNzZW50aWFsIHdoZW4gYW5hbHl6aW5nIHNwYXRpYWwgZGF0YSBwcm9uZSB0byBTaW1wc29u4oCZcyBQYXJhZG94IOKAlCB3aGVyZSBhIHRyZW5kIG9ic2VydmVkIGluIGFnZ3JlZ2F0ZSBkYXRhIGNhbiBkaWZmZXIgZnJvbSB0cmVuZHMgaW4gc3Vic2V0cy4gR1dSIGFsbG93cyB1cyB0byBleGFtaW5lIHJlbGF0aW9uc2hpcHMgYXQgYSBsb2NhbCBsZXZlbCByYXRoZXIgdGhhbiBhc3N1bWluZyB0aGV5IGFyZSB1bmlmb3JtIGFjcm9zcyB0aGUgc3R1ZHkgYXJlYS4gVGhlIGdlbmVyYWwgR1dSIGVxdWF0aW9uIGNhbiBiZSBleHByZXNzZWQgYXM6CgoKJCQKeV9pID0gXGJldGFfe2kwfSArIFxzdW1fe2s9MX1ee219IFxiZXRhX3tpa314X3tpa30gKyBcZXBzaWxvbl9pCiQkCgp3aGVyZTogXCggeV9pIFwpIGlzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYXQgbG9jYXRpb24gXChpXCksIFwoIFxiZXRhX3tpMH0gXCkgaXMgdGhlIGludGVyY2VwdCBmb3IgbG9jYXRpb24gXChpXCksIGFsbG93aW5nIGEgdW5pcXVlIGJhc2VsaW5lIGZvciBlYWNoIGxvY2F0aW9uLCBcKCBcYmV0YV97aWt9IFwpIGlzIHRoZSBjb2VmZmljaWVudCBmb3IgdGhlIFwoa1wpLXRoIHByZWRpY3RvciBhdCBsb2NhdGlvbiBcKGlcKSwgXCggeF97aWt9IFwpIGlzIHRoZSB2YWx1ZSBvZiB0aGUgXChrXCktdGggcHJlZGljdG9yIHZhcmlhYmxlIGF0IGxvY2F0aW9uIFwoaVwpLCBhbmQgXCggXGVwc2lsb25faSBcKSBpcyB0aGUgZXJyb3IgdGVybSBhdCBsb2NhdGlvbiBcKGlcKS4KCkluIEdXUiwgbG9jYWwgcmVncmVzc2lvbiBpcyBwZXJmb3JtZWQgYnkgZml0dGluZyBhIHJlZ3Jlc3Npb24gbW9kZWwgYXQgZWFjaCBvYnNlcnZhdGlvbiBwb2ludCwgdXNpbmcgYSBzdWJzZXQgb2YgbmVpZ2hib3JpbmcgcG9pbnRzLCB3aXRoIHdlaWdodHMgYXNzaWduZWQgYmFzZWQgb24gdGhlaXIgZGlzdGFuY2UgZnJvbSB0aGUgZm9jYWwgcG9pbnQuIFRoZSBjb25jZXB0IG9mIGJhbmR3aWR0aCBjb250cm9scyB0aGUgbnVtYmVyIG9mIG5laWdoYm9ycyBpbmNsdWRlZCwgaW5mbHVlbmNpbmcgaG93ICJsb2NhbCIgZWFjaCByZWdyZXNzaW9uIGlzLiBUaGVyZSBhcmUgdHdvIHR5cGVzIG9mIGJhbmR3aWR0aHM6IGFkYXB0aXZlIGFuZCBmaXhlZC4gQSBmaXhlZCBiYW5kd2lkdGggdXNlcyBhIGNvbnN0YW50IGRpc3RhbmNlIGZvciBhbGwgcG9pbnRzLCB3aGlsZSBhbiBhZGFwdGl2ZSBiYW5kd2lkdGggdmFyaWVzLCBhZGp1c3RpbmcgdG8gaW5jbHVkZSBhIHNldCBudW1iZXIgb2YgbmVhcmJ5IG9ic2VydmF0aW9ucyByZWdhcmRsZXNzIG9mIHNwYXRpYWwgZGVuc2l0eS4gSGVyZSwgd2Ugd2lsbCB1c2UgYWRhcHRpdmUgYmFuZHdpZHRoLCB3aGljaCBpcyBtb3JlIGFwcHJvcHJpYXRlIGFzIGl0IGFjY291bnRzIGZvciB2YXJ5aW5nIHNwYXRpYWwgZGVuc2l0aWVzLCBwcm92aWRpbmcgYSBmbGV4aWJsZSBhbmFseXNpcyB0aGF0IGJldHRlciBjYXB0dXJlcyBsb2NhbCByZWxhdGlvbnNoaXBzIGluIGFyZWFzIHdpdGggZGlmZmVyZW50IHBvcHVsYXRpb24gZGlzdHJpYnV0aW9ucy4KCkFsdGhvdWdoIEdXUiBhbGxvd3MgZm9yIHNwYXRpYWwgdmFyaWF0aW9uIGluIHJlbGF0aW9uc2hpcHMsIHRoZSBzdGFuZGFyZCBPTFMgYXNzdW1wdGlvbnMgKGxpbmVhcml0eSwgaW5kZXBlbmRlbmNlLCBob21vc2NlZGFzdGljaXR5LCBhbmQgbm9ybWFsaXR5KSBzdGlsbCBhcHBseS4gTXVsdGljb2xsaW5lYXJpdHkgaXMgYXNzZXNzZWQgdXNpbmcgdGhlIENvbmRpdGlvbiBOdW1iZXIsIGFuZCBoaWdoIG11bHRpY29sbGluZWFyaXR5IGNhbiBjYXVzZSBpc3N1ZXMgaW4gR1dSLCBsZWFkaW5nIHRvIHVuc3RhYmxlIGVzdGltYXRlcyBhbmQgY2x1c3RlcmluZyBpbiBwYXJhbWV0ZXIgZXN0aW1hdGVzLiBJdCBpcyBhbHNvIGltcG9ydGFudCB0byBub3RlIHRoYXQgR1dSIGRvZXMgbm90IHByb3ZpZGUgcC12YWx1ZXMgZm9yIGNvZWZmaWNpZW50cywgYXMgdGhlIG1vZGVsIGZvY3VzZXMgb24gZXhwbG9yaW5nIHNwYXRpYWwgcGF0dGVybnMgcmF0aGVyIHRoYW4gdGVzdGluZyBnbG9iYWwgaHlwb3RoZXNlcy4KCgojIFJlc3VsdHMKCiMjIEdsb2JhbCBhbmQgTG9jYWwgTW9yYW4ncyBJCgpUaGUgR2xvYmFsIE1vcmFuJ3MgSSBhbmFseXNpcyBmb3IgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgXChcdGV4dHtMTk1FREhWQUx9XCkgKHRoZSBuYXR1cmFsIGxvZyBvZiBtZWRpYW4gaG91c2UgdmFsdWUpLCByZXZlYWxzIGEgcHJvbm91bmNlZCBsZXZlbCBvZiBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gV2l0aCBhIE1vcmFuJ3MgSSBzdGF0aXN0aWMgb2YgMC44LCB0aGUgcmVzdWx0cyBpbmRpY2F0ZSBhIHN0cm9uZyBwb3NpdGl2ZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVGhpcyBoaWdoIHZhbHVlIHN1Z2dlc3RzIHRoYXQgYXJlYXMgd2l0aCBzaW1pbGFyIG1lZGlhbiBob3VzZSB2YWx1ZXMgdGVuZCB0byBjbHVzdGVyIGdlb2dyYXBoaWNhbGx5IHdpdGhpbiB0aGUgc3R1ZHkgYXJlYS4gSW4gb3RoZXIgd29yZHMsIG5laWdoYm9yaG9vZHMgd2l0aCBlaXRoZXIgaGlnaCBvciBsb3cgaG91c2UgdmFsdWVzIGFyZSBtb3JlIGxpa2VseSB0byBiZSBsb2NhdGVkIG5lYXIgb3RoZXIgbmVpZ2hib3Job29kcyB3aXRoIHNpbWlsYXIgdmFsdWVzLCByYXRoZXIgdGhhbiBiZWluZyByYW5kb21seSBkaXN0cmlidXRlZCBhY3Jvc3Mgc3BhY2UuIFRoaXMgc3BhdGlhbCBjbHVzdGVyaW5nIHBvaW50cyB0byB0aGUgcHJlc2VuY2Ugb2Ygc3BhdGlhbCBkZXBlbmRlbmNpZXMgaW4gaG91c2luZyB2YWx1ZXMsIHBvc3NpYmx5IGRyaXZlbiBieSBuZWlnaGJvcmhvb2QgY2hhcmFjdGVyaXN0aWNzLCBzb2Npby1lY29ub21pYyBmYWN0b3JzLCBvciBvdGhlciBzcGF0aWFsIHByb2Nlc3NlcyBpbmZsdWVuY2luZyBwcm9wZXJ0eSB2YWx1ZXMgYWNyb3NzIHRoZSByZWdpb24uCgpUbyB2YWxpZGF0ZSB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoaXMgb2JzZXJ2ZWQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIGEgTW9udGUgQ2FybG8gcGVybXV0YXRpb24gdGVzdCB3YXMgY29uZHVjdGVkIHVzaW5nIDEwMDAgc2ltdWxhdGlvbnMuIFRoaXMgYXBwcm9hY2ggaW52b2x2ZWQgcmFuZG9tbHkgcGVybXV0aW5nIHRoZSB2YWx1ZXMgb2YgXChcdGV4dHtMTk1FREhWQUx9XCkgYWNyb3NzIHNwYXRpYWwgdW5pdHMgdG8gZ2VuZXJhdGUgYSBkaXN0cmlidXRpb24gb2YgTW9yYW4ncyBJIHZhbHVlcyB1bmRlciB0aGUgbnVsbCBoeXBvdGhlc2lzIG9mIG5vIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLiBUaGUgcmVzdWx0cywgdmlzdWFsaXplZCBpbiBhIGhpc3RvZ3JhbSBvZiBwZXJtdXRlZCBNb3JhbuKAmXMgSSB2YWx1ZXMsIHNob3cgdGhhdCB0aGUgb2JzZXJ2ZWQgTW9yYW7igJlzIEkgb2YgMC44IGxpZXMgYXQgdGhlIGV4dHJlbWUgZW5kIG9mIHRoaXMgZGlzdHJpYnV0aW9uLCBtYXJrZWQgaW4gcmVkLiBXaXRoIGFuIG9ic2VydmVkIHJhbmsgb2YgMTAwMCAodGhlIGhpZ2hlc3QgcmFuayBpbiB0aGUgZGlzdHJpYnV0aW9uKSwgdGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIHZhbHVlIGV4Y2VlZGVkIGFsbCBwZXJtdXRlZCB2YWx1ZXMsIGVtcGhhc2l6aW5nIHRoZSBleHRyZW1pdHkgb2YgdGhlIHNwYXRpYWwgY2x1c3RlcmluZyBpbiB0aGUgYWN0dWFsIGRhdGEuCgpUaGUgdGVzdCByZXN1bHQgaXMgZnVydGhlciBzdXBwb3J0ZWQgYnkgYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSAoXCggcCA8IDIgXHRpbWVzIDEwXnstMTZ9IFwpKS4gVGhpcyBleGNlcHRpb25hbGx5IGxvdyBwLXZhbHVlIHN0cm9uZ2x5IHJlamVjdHMgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgY29uZmlybWluZyB0aGF0IHRoZSBzcGF0aWFsIGFycmFuZ2VtZW50IG9mIFwoXHRleHR7TE5NRURIVkFMfVwpIHZhbHVlcyBpcyBub3QgcmFuZG9tLiBJbnN0ZWFkLCB0aGUgb2JzZXJ2ZWQgY2x1c3RlcmluZyBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBpbmRpY2F0aW5nIHRoYXQgc3BhdGlhbCBwcm9jZXNzZXMgYXJlIGxpa2VseSBpbmZsdWVuY2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGhvdXNpbmcgdmFsdWVzIGluIHRoZSBzdHVkeSBhcmVhLgoKYGBge3IgY29uc3RydWN0IHF1ZWVuIG5laWdoYm9ycywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCnF1ZWVuPC1wb2x5Mm5iKHJlZ0RhdGEsIHJvdy5uYW1lcz1yZWdEYXRhJFBPTFlfSUQpCnF1ZWVubGlzdDwtbmIybGlzdHcocXVlZW4sIHN0eWxlID0gJ1cnKQoKYGBgCgoKYGBge3IgZ2xvYmFsIG1vcmFuIEksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnbG9iYWxtb3Jhbk1DPC1tb3Jhbi5tYyhyZWdEYXRhJExOTUVESFZBTCwgcXVlZW5saXN0LCBuc2ltPTk5OSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIpIApnbG9iYWxtb3Jhbk1DCgpgYGAKClRoaXMgZ3JhcGggc2hvd3MgdGhlIHJlc3VsdHMgb2YgdGhlIE1vbnRlIENhcmxvIHBlcm11dGF0aW9uIHRlc3QgdG8gYXNzZXNzIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIHN0YXRpc3RpYy5UaGUgaGlzdG9ncmFtIHNob3dzIHRoZSBmcmVxdWVuY3kgb2YgTW9yYW4ncyBJIHZhbHVlcyBnZW5lcmF0ZWQgYnkgdGhlc2UgcmFuZG9tIHBlcm11dGF0aW9ucywgd2l0aCB0aGUgb2JzZXJ2ZWQgTW9yYW7igJlzIEkgdmFsdWUgaGlnaGxpZ2h0ZWQgaW4gcmVkLiBUaGUgb2JzZXJ2ZWQgc3RhdGlzdGljIG9mIDAuOCBzdGFuZHMgZmFyIHRvIHRoZSByaWdodCBvZiB0aGUgcGVybXV0ZWQgdmFsdWVzLCB1bmRlcnNjb3JpbmcgaXRzIGV4dHJlbWl0eSBhbmQgc2lnbmlmaWNhbmNlLiBUaGUgaGlnaCBvYnNlcnZlZCByYW5rICgxMDAwKSBpbmRpY2F0ZXMgdGhhdCBub25lIG9mIHRoZSBwZXJtdXRlZCB2YWx1ZXMgZXhjZWVkZWQgdGhlIGFjdHVhbCBNb3JhbuKAmXMgSS4gVGhpcyBleHRyZW1lbHkgbG93IHAtdmFsdWUgcHJvdmlkZXMgc3Ryb25nIGV2aWRlbmNlIGFnYWluc3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgY29uZmlybWluZyB0aGF0IHRoZSBzcGF0aWFsIGNsdXN0ZXJpbmcgb2JzZXJ2ZWQgaW4gXChcdGV4dHtMTk1FREhWQUx9XCkgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhbmQgdW5saWtlbHkgdG8gYmUgZHVlIHRvIHJhbmRvbSB2YXJpYXRpb24uCgpgYGB7ciBnbG9iYWwgbW9yYW4gaGlzdG9ncmFtIHBsb3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnZ3Bsb3QoZGF0YS5mcmFtZShyZXMgPSBnbG9iYWxtb3Jhbk1DJHJlcyksIGFlcyh4ID0gcmVzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDAsIGZpbGwgPSAiIzI4M2QzYiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBnbG9iYWxtb3Jhbk1DJHN0YXRpc3RpYywgY29sb3IgPSAiI2M0NDUzNiIsIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJPYnNlcnZlZCBhbmQgUGVybXV0ZWQgR2xvYmFsIE1vcmFuJ3MgSSIsCiAgICAgICBzdWJ0aXRsZSA9ICJPYnNlcnZlZCBNb3JhbidzIEkgaW4gUmVkIiwKICAgICAgIHggPSAiTW9yYW4ncyBJIiwKICAgICAgIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpgYGAKClRoaXMgZ3JhcGggb2ZmZXJzIGEgZGlmZmVyZW50IHBlcnNwZWN0aXZlIG9uIHRoZSBzcGF0aWFsIHN0cnVjdHVyZSBvZiBcKFx0ZXh0e0xOTUVESFZBTH1cKSBieSBkaXNwbGF5aW5nIGEgc2NhdHRlciBwbG90IG9mIHRoZSB2YXJpYWJsZeKAmXMgdmFsdWVzIGFnYWluc3QgdGhlaXIgc3BhdGlhbCBsYWcgKGEgbWVhc3VyZSBvZiBuZWlnaGJvcmluZyB2YWx1ZXMpLiBUaGUgeC1heGlzIHJlcHJlc2VudHMgdGhlIGxvZ2dlZCBtZWRpYW4gaG91c2UgdmFsdWVzIFwoXHRleHR7TE5NRURIVkFMfVwpLCB3aGlsZSB0aGUgeS1heGlzIGRpc3BsYXlzIHRoZSBzcGF0aWFsbHkgbGFnZ2VkIHZhbHVlcyBvZiAgXChcdGV4dHtMTk1FREhWQUx9XCksIGNvbXB1dGVkIGJhc2VkIG9uIGEgcXVlZW4gY29udGlndWl0eSBzcGF0aWFsIHdlaWdodHMgbWF0cml4IHRoYXQgY29uc2lkZXJzIG5laWdoYm9yaW5nIHNwYXRpYWwgdW5pdHMuIFRoZSBwb3NpdGl2ZSBzbG9wZSBvZiB0aGUgcmVkIHRyZW5kIGxpbmUgaW4gdGhlIHNjYXR0ZXIgcGxvdCBpbmRpY2F0ZXMgYSBwb3NpdGl2ZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgd2hlcmUgYXJlYXMgd2l0aCBoaWdoZXIgbWVkaWFuIGhvdXNlIHZhbHVlcyBhcmUgdHlwaWNhbGx5IHN1cnJvdW5kZWQgYnkgb3RoZXIgYXJlYXMgd2l0aCBoaWdoIHZhbHVlcywgYW5kIHNpbWlsYXJseSwgYXJlYXMgd2l0aCBsb3dlciB2YWx1ZXMgYXJlIG5lYXIgb3RoZXIgbG93LXZhbHVlIGFyZWFzLiBUaGlzIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGxvY2F0aW9u4oCZcyBcKFx0ZXh0e0xOTUVESFZBTH1cKSBhbmQgdGhlIGF2ZXJhZ2UgdmFsdWVzIGluIHN1cnJvdW5kaW5nIGxvY2F0aW9ucyBoaWdobGlnaHRzIHRoZSBjbHVzdGVyaW5nIG9mIHNpbWlsYXIgdmFsdWVzIGFuZCBzdXBwb3J0cyB0aGUgcmVzdWx0IGZyb20gdGhlIEdsb2JhbCBNb3JhbuKAmXMgSSBzdGF0aXN0aWMuCgpgYGB7ciBnbG9iYWwgbW9yYW4gc2NhdHRlciBwbG90LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIExOTUVESFZBTCA9IHJlZ0RhdGEkTE5NRURIVkFMLAogIHNwYXRpYWxfbGFnID0gbGFnLmxpc3R3KHF1ZWVubGlzdCwgcmVnRGF0YSRMTk1FREhWQUwpCiksIGFlcyh4ID0gTE5NRURIVkFMLCB5ID0gc3BhdGlhbF9sYWcpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMjgzZDNiIiwgYWxwaGEgPSAwLjcsIHNpemUgPSAwLjYpICsgIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gIiNjNDQ1MzYiLCBzZSA9IEZBTFNFKSArIAogIGxhYnModGl0bGUgPSAiR2xvYmFsIE1vcmFuJ3MgSSBTY2F0dGVyIFBsb3QiLAogICAgICAgeCA9ICJMb2dnZWQgTWVkaWFuIEhvdXNlIFZhbHVlIiwKICAgICAgIHkgPSAiU3BhdGlhbCBMYWcgb2YgTE5NRURIVkFMIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQoKYGBgCgoKYGBge3IgY29tcHV0ZSBsb2NhbCBtb3JhbiBJLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKbG9jYWxtb3JhbiA8LWxvY2FsbW9yYW4ocmVnRGF0YSRMTk1FREhWQUwgLCBxdWVlbmxpc3QpCmxvY2FsbW9yYW4gPC1jYmluZChyZWdEYXRhLCBhcy5kYXRhLmZyYW1lKGxvY2FsbW9yYW4pKQoKYGBgCgpJbiBhIExvY2FsIE1vcmFuJ3MgSSBzaWduaWZpY2FuY2UgbWFwLCBhcmVhcyB3aXRoIHNpZ25pZmljYW50IGxvdyBwLXZhbHVlcyByZWZlcnMgdG8gYXJlYSB3aGVyZSB0aGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgZWl0aGVyIGhvdHNwb3RzIG9mIGNvbmNlbnRyYXRlZCBoaWdoIHZhbHVlcyBvciBjb2xkIHNwb3RzIG9mIGxvdyB2YWx1ZXMuIFRoZXJlIGFyZWFzIGFyZSBtb3N0bHkgZm91bmQgaW4gdGhlIG5vcnRod2VzdGVybiBhbmQgY2VudHJhbCBwYXJ0cyBvZiB0aGUgY2l0eS4gQXMgd2UgbWF5IHNlZSwgdGhlc2UgYXJlYXMgYXJlIHRoZW4gc3Vycm91bmRlZCBieSBhcmVhcyB3aXRoIHNsaWdodGx5IGhpZ2hlciBwLXZhbHVlcyBhbmQgdGhlbiBhcmVhcyB3aXRoIGV2ZW4gaGlnaGVyIHAtdmFsdWVzLCB1bnRpbCBwIGJlY29tZXMgaW5zaWduaWZpY2FudC4gCgpgYGB7ciBsb2NhbCBtb3JhbiBzaWduaWZpY2FuY2UgbWFwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbW9yYW5TaWcucGxvdCA8LSBmdW5jdGlvbihkZiwgbGlzdHcsIHRpdGxlKSB7CiAgCiAgbG9jYWwgPC0gbG9jYWxtb3Jhbih4ID0gZGYkTE5NRURIVkFMLCBsaXN0dyA9IGxpc3R3LCB6ZXJvLnBvbGljeSA9IEZBTFNFKQogIAogIGRmJFByLnogPC0gbG9jYWxbLCAgIlByKHogIT0gRShJaSkpIl0gIAogIAogIGRmJHB2YWxfY2F0ZWdvcnkgPC0gY3V0KGRmJFByLnosIAogICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMCwgMC4wMDEsIDAuMDEsIDAuMDUsIDEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwLjAwMCAtIDAuMDAxIiwgIjAuMDAxIC0gMC4wMTAiLCAiMC4wMTAgLSAwLjA1MCIsICIwLjA1MCAtIDEuMDAwIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkKICAKICBpZiAoIWluaGVyaXRzKGRmLCAic2YiKSkgewogICAgZGYgPC0gc3RfYXNfc2YoZGYpCiAgfQogIAogIGdncGxvdChkYXRhID0gZGYpICsKICAgIGdlb21fc2YoYWVzKGZpbGwgPSBwdmFsX2NhdGVnb3J5KSwgY29sb3IgPSBOQSwgYWxwaGEgPSAwLjkpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAiZGl2IiwgcGFsZXR0ZSA9IDYsIG5hbWUgPSAiUC1WYWx1ZSIpICsKICAgIGxhYnModGl0bGUgPSB0aXRsZSkgKwogICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIHNpemUgPSAwLjgpKQp9Cgptb3JhblNpZy5wbG90KGxvY2FsbW9yYW4sIHF1ZWVubGlzdCwgJ1NpZ25pZmljYW5jZSBNYXAgb2YgTG9jYWwgTW9yYW4gSScpCgpgYGAKClRoZSBDbHVzdGVyIE1hcCBkZXJpdmVkIGZyb20gdGhlIExvY2FsIE1vcmFu4oCZcyBJIGFuYWx5c2lzIGNsYXNzaWZpZWQgY2Vuc3VzIHRyYWN0cyBpbiBQaGlsYWRlbHBoaWEgaW50byAgaGlnaC1oaWdoLCBoaWdoLWxvdywgbG93LWhpZ2gsIGxvdy1sb3csIG9yIG5vdCBzaWduaWZpY2FudCwgcmVwcmVzZW50aW5nIGRpZmZlcmVudCB0eXBlcyBvZiBzcGF0aWFsIHJlbGF0aW9uc2hpcHMgaW4gaG91c2UgdmFsdWVzIHdpdGhpbiBuZWlnaGJvcmhvb2RzIGFuZCB0aGVpciBzdXJyb3VuZGluZ3MuCgoqKkhpZ2gtSGlnaCBDbHVzdGVycyoqOiBBcmVhcyBjbGFzc2lmaWVkIGFzIGhpZ2gtaGlnaCBhcmUgdGhvc2Ugd2hlcmUgaGlnaCB2YWx1ZXMgb2YgbWVkaWFuIGhvdXNlIHByaWNlcyBhcmUgc3Vycm91bmRlZCBieSBvdGhlciBoaWdoLXZhbHVlIGFyZWFzLiBUaGVzZSBjbHVzdGVycyBhcmUgcHJvbWluZW50bHkgbG9jYXRlZCBpbiB0aGUgbm9ydGh3ZXN0ZXJuIHBhcnRzIG9mIHRoZSBjaXR5IGFuZCBzb21lIGNlbnRyYWwgcmVnaW9ucywgaW5kaWNhdGluZyBwb2NrZXRzIG9mIGVjb25vbWljIGFmZmx1ZW5jZS4gVGhlIGhpZ2ggY29uY2VudHJhdGlvbiBvZiBoaWdoLXZhbHVlIHByb3BlcnRpZXMgaW4gdGhlc2UgcmVnaW9ucyBzdWdnZXN0cyBlc3RhYmxpc2hlZCwgYWZmbHVlbnQgbmVpZ2hib3Job29kcyB3aGVyZSBob3VzaW5nIHByaWNlcyByZW1haW4gaGlnaCBkdWUgdG8gZGVtYW5kIGFuZCBwb3NzaWJseSB0aGUgcHJlc2VuY2Ugb2YgYW1lbml0aWVzIG9yIG90aGVyIGF0dHJhY3RpdmUgdXJiYW4gZmVhdHVyZXMuCgoqKkxvdy1Mb3cgQ2x1c3RlcnMqKjogTG93LWxvdyBjbHVzdGVycyByZXByZXNlbnQgYXJlYXMgd2hlcmUgbG93IHByb3BlcnR5IHZhbHVlcyBhcmUgc3Vycm91bmRlZCBieSBvdGhlciBsb3ctdmFsdWUgYXJlYXMsIGhpZ2hsaWdodGluZyBlY29ub21pY2FsbHkgZGlzYWR2YW50YWdlZCB6b25lcy4gVGhlc2UgY2x1c3RlcnMgYXJlIHByZWRvbWluYW50bHkgZm91bmQgaW4gdGhlIHNvdXRod2VzdGVybiBhbmQgbm9ydGhlYXN0ZXJuIHBhcnRzIG9mIHRoZSBjaXR5LiBUaGUgc3BhdGlhbCBjbHVzdGVyaW5nIG9mIGxvdy12YWx1ZSBwcm9wZXJ0aWVzIGluIHRoZXNlIGFyZWFzIHN1Z2dlc3RzIG5laWdoYm9yaG9vZHMgdGhhdCBtYXkgZmFjZSBlY29ub21pYyBjaGFsbGVuZ2VzLCBwb3NzaWJseSB3aXRoIGxpbWl0ZWQgYWNjZXNzIHRvIGFtZW5pdGllcyBvciBmZXdlciBpbnZlc3RtZW50IG9wcG9ydHVuaXRpZXMuIFRoZXNlIHJlZ2lvbnMgbWF5IHJlcXVpcmUgdGFyZ2V0ZWQgcG9saWN5IGludGVydmVudGlvbnMgdG8gYWRkcmVzcyB1bmRlcmx5aW5nIGlzc3VlcyB0aGF0IGNvbnRyaWJ1dGUgdG8gdGhlIGxvd2VyIHByb3BlcnR5IHZhbHVlcy4KCioqSGlnaC1Mb3cgQ2x1c3RlcnMqKjogSGlnaC1sb3cgY2x1c3RlcnMgYXJlIHRyYW5zaXRpb25hbCB6b25lcyB3aGVyZSBoaWdoLXZhbHVlIGFyZWFzIGFyZSBhZGphY2VudCB0byBsb3dlci12YWx1ZSBhcmVhcy4gVGhlc2UgYXJlYXMsIG1hcmtlZCBpbiBsaWdodCByZWQgb24gdGhlIG1hcCwgYXJlIGdlbmVyYWxseSBzY2F0dGVyZWQgYXJvdW5kIHRoZSBib3VuZGFyaWVzIG9mIGhpZ2gtdmFsdWUgbmVpZ2hib3Job29kcywgc3VjaCBhcyBpbiBzZWN0aW9ucyBvZiBjZW50cmFsIGFuZCBub3J0aHdlc3QgUGhpbGFkZWxwaGlhLiBUaGUgcHJveGltaXR5IG9mIGhpZ2gtdmFsdWUgcHJvcGVydGllcyB0byBsb3dlci12YWx1ZSBvbmVzIGluIHRoZXNlIGNsdXN0ZXJzIGNhbiBpbmRpY2F0ZSBlY29ub21pYyBjb250cmFzdHMgb3IgYXJlYXMgZXhwZXJpZW5jaW5nIGdlbnRyaWZpY2F0aW9uLCB3aGVyZSBwcm9wZXJ0eSB2YWx1ZXMgaW4gdHJhZGl0aW9uYWxseSBsb3dlci1pbmNvbWUgbmVpZ2hib3Job29kcyBtYXkgYmUgaW5jcmVhc2luZyBkdWUgdG8gc3BpbGxvdmVyIGVmZmVjdHMgZnJvbSBuZWFyYnkgYWZmbHVlbnQgYXJlYXMuCgoqKkxvdy1IaWdoIENsdXN0ZXJzKio6IExvdy1oaWdoIGNsdXN0ZXJzLCB3aGVyZSBsb3ctdmFsdWUgcHJvcGVydGllcyBhcmUgc3Vycm91bmRlZCBieSBoaWdoZXItdmFsdWUgYXJlYXMsIGFyZSBsZXNzIGNvbW1vbiBidXQgYXBwZWFyIGluIHRoZSBub3J0aGVybiBhbmQgZWFzdGVybiBwYXJ0cyBvZiB0aGUgY2l0eS4gVGhlc2UgY2x1c3RlcnMgc3VnZ2VzdCBpc29sYXRlZCBwb2NrZXRzIG9mIGVjb25vbWljIGRpc2FkdmFudGFnZSB3aXRoaW4gbW9yZSBhZmZsdWVudCBhcmVhcy4gVGhpcyBwYXR0ZXJuIG1heSBpbmRpY2F0ZSBhcmVhcyB0aGF0IGFyZSB5ZXQgdG8gYmVuZWZpdCBmcm9tIHN1cnJvdW5kaW5nIGVjb25vbWljIGdyb3d0aCBvciBtaWdodCBiZSBleHBlcmllbmNpbmcgY2hhbGxlbmdlcyB0aGF0IHByZXZlbnQgdGhlbSBmcm9tIGFsaWduaW5nIHdpdGggdGhlIHByb3NwZXJpdHkgb2YgbmVpZ2hib3JpbmcgcmVnaW9ucy4KCioqTm90IFNpZ25pZmljYW50IEFyZWFzKio6IExhc3RseSwgdGhlIG5vdCBzaWduaWZpY2FudCBhcmVhcywgc2hhZGVkIGluIGdyYXksIGluZGljYXRlIG5laWdoYm9yaG9vZHMgd2hlcmUgdGhlIGxvY2FsIE1vcmFu4oCZcyBJIHN0YXRpc3RpYyB3YXMgbm90IHNpZ25pZmljYW50LiBUaGVzZSByZWdpb25zIGFyZSBzY2F0dGVyZWQgdGhyb3VnaG91dCB0aGUgY2l0eSwgcmVwcmVzZW50aW5nIGFyZWFzIHdoZXJlIGhvdXNlIHZhbHVlcyBkbyBub3QgZXhoaWJpdCBzdHJvbmcgc3BhdGlhbCBjbHVzdGVyaW5nLiBUaGUgbGFjayBvZiBzaWduaWZpY2FudCBjbHVzdGVyaW5nIGluIHRoZXNlIGFyZWFzIHN1Z2dlc3RzIGEgbW9yZSByYW5kb20gZGlzdHJpYnV0aW9uIG9mIGhvdXNlIHZhbHVlcywgd2hpY2ggbWF5IG9jY3VyIGluIG1vcmUgbWl4ZWQtdXNlIG9yIHRyYW5zaXRpb25hbCBuZWlnaGJvcmhvb2RzIHdoZXJlIGVjb25vbWljIGNoYXJhY3RlcmlzdGljcyBhcmUgdmFyaWVkLgoKCmBgYHtyIGxvY2FsIG1vcmFuIGNsdXN0ZXIgbWFwLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhsLnBsb3QgPC0gZnVuY3Rpb24oZGYsIGxpc3R3KSB7CgogIGxvY2FsIDwtIGxvY2FsbW9yYW4oeCA9IGRmJExOTUVESFZBTCwgbGlzdHcgPSBsaXN0dywgemVyby5wb2xpY3kgPSBGQUxTRSkKICBxdWFkcmFudCA8LSB2ZWN0b3IobW9kZSA9ICdudW1lcmljJywgbGVuZ3RoID0gbnJvdyhkZikpICAKICAKICBtLnByb3AgPC0gZGYkTE5NRURIVkFMIC0gbWVhbihkZiRMTk1FREhWQUwpCiAgbS5sb2NhbCA8LSBsb2NhbFssIDFdIC0gbWVhbihsb2NhbFssIDFdKQogIHNpZ25pZiA8LSAwLjA1CiAgCiAgcXVhZHJhbnRbbS5wcm9wID4gMCAmIG0ubG9jYWwgPiAwXSA8LSAxICAjIGhpZ2gtaGlnaAogIHF1YWRyYW50W20ucHJvcCA8IDAgJiBtLmxvY2FsIDwgMF0gPC0gMiAgIyBsb3ctbG93CiAgcXVhZHJhbnRbbS5wcm9wIDwgMCAmIG0ubG9jYWwgPiAwXSA8LSA0ICAjIGxvdy1oaWdoCiAgcXVhZHJhbnRbbS5wcm9wID4gMCAmIG0ubG9jYWwgPCAwXSA8LSAzICAjIGhpZ2gtbG93CiAgcXVhZHJhbnRbbG9jYWxbLCA1XSA+IHNpZ25pZl0gPC0gNSAgIyBpbnNpZ25pZmljYW50CiAgCiAgZGYkcXVhZHJhbnQgPC0gZmFjdG9yKHF1YWRyYW50LCBsZXZlbHMgPSBjKDEsIDMsIDUsIDIsIDQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiSGlnaC1IaWdoIiwgIkhpZ2gtTG93IiwgIk5vbi1TaWduaWZpY2FudCIsICJMb3ctTG93IiwgIkxvdy1IaWdoIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgaWYgKCFpbmhlcml0cyhkZiwgInNmIikpIHsKICAgIGRmIDwtIHN0X2FzX3NmKGRmKQogIH0KICAKICBnZ3Bsb3QoZGF0YSA9IGRmKSArCiAgICBnZW9tX3NmKGFlcyhmaWxsID0gcXVhZHJhbnQpLCBjb2xvciA9ICIjODQ4ODg0IiwgbHdkID0gMC4wNykgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIodHlwZSA9ICJkaXYiLCBwYWxldHRlID0gNiwgbmFtZSA9ICJDbHVzdGVyIFR5cGUiKSArIAogICAgbGFicyh0aXRsZSA9ICJMb2NhbCBNb3JhbidzIEkgQ2x1c3RlciBNYXAiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IiwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBsaW5ld2lkdGg9MC44KQogICAgICAgICkKfQoKaGwucGxvdChyZWdEYXRhLCBxdWVlbmxpc3QpCgpgYGAKCiMjIE9MUyBSZWdyZXNzaW9uIFJlc3VsdHMKCkJlbG93LCB3ZSB3aWxsIHByb3ZpZGUgYSBxdWljayB3YWxrIHRocm91Z2ggb2YgdGhlIE9MUyByZWdyZXNzaW9uIHJlc3VsdHMuIERldGFpbCBpbnRlcnByZXRhdGlvbiBhbmQgZGljdXNzaW9uIG9mIHRoZSByZXN1bHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgW0dpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vZW1pbHl6aG91MTEyL0NQTE42NzEtT0xTLVJlZ3Jlc3Npb24pIGZvciBhc3NpZ25tZW50IDEuCgpBbGwgcHJlZGljdG9ycyBpbiBvdXIgT0xTIHJlZ3Jlc3Npb24sIHdoaWNoIGluY2x1ZGUgXChcdGV4dHtQQ1RTSU5HTEVTfVwpLCBcKFx0ZXh0e1BDVFZBQ0FOVH1cKSwgXChcdGV4dHtMTk5CRUxQT1Z9XCksIGFuZCBcKFx0ZXh0e1BDVEJBQ0hNT1J9XCksIGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGluIGV4cGxhaW5pbmcgXChcdGV4dHtMTk1FREhWQUx9XCkuIFRoZSBtb2RlbCBhY2NvdW50cyBmb3IgYXBwcm94aW1hdGVseSA2Ni4yJSBvZiB0aGUgdmFyaWFuY2UsIGFzIGluZGljYXRlZCBieSB0aGUgUi1zcXVhcmVkIHZhbHVlIG9mIDAuNjYyLgoKCmBgYHtyIG9scyByZWdyZXNzaW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKT0xTIDwtIGxtKExOTUVESFZBTCB+IFBDVFZBQ0FOVCArIFBDVFNJTkdMRVMgKyBQQ1RCQUNITU9SICsgTE5OQkVMUE9WLCBkYXRhPXJlZ0RhdGEpCmZpdHRlZF92YWx1ZXMgPC0gZml0dGVkKE9MUykKcmVzaWR1YWxzX3ZhbHVlcyA8LSByZXNpZHVhbHMoT0xTKQpzdGFuZGFyZGl6ZWRfcmVzaWR1YWxzIDwtIHJzdGFuZGFyZChPTFMpCnJlc25iPC1zYXBwbHkocXVlZW4sIGZ1bmN0aW9uKHgpIG1lYW4oc3RhbmRhcmRpemVkX3Jlc2lkdWFsc1t4XSkpCnJlZ0RhdGEgPC0gcmVnRGF0YSAlPiUKICBtdXRhdGUoCiAgICBGaXR0ZWQgPSBmaXR0ZWRfdmFsdWVzLAogICAgUmVzaWR1YWxzID0gcmVzaWR1YWxzX3ZhbHVlcywKICAgIFN0YW5kYXJkaXplZF9SZXNpZHVhbHMgPSBzdGFuZGFyZGl6ZWRfcmVzaWR1YWxzLAogICAgUmVzaWR1YWxzX05CID0gcmVzbmIpCgpzdW1tYXJ5KE9MUykKCmBgYAoKVGhlIHJlc3VsdHMgZnJvbSB0aGUgQnJldXNjaC1QYWdhbiwgS29lbmtlci1CYXNzZXR0LCBhbmQgV2hpdGUncyB0ZXN0cyBhbGwgZGV0ZWN0IGhldGVyb3NjZWRhc3RpY2l0eSBpbiB0aGUgbW9kZWwsIGFzIGFsbCBwLXZhbHVlcyBhcmUgZXh0cmVtZWx5IGxvdy4gVGhpcyBjb25maXJtcyBhIGNsZWFyIHZpb2xhdGlvbiBvZiB0aGUgaG9tb3NjZWRhc3RpY2l0eSBhc3N1bXB0aW9uIGluIE9MUyByZWdyZXNzaW9uLiAKCmBgYHtyIGhldGVyb3NjZWRhc3RpY2l0eSB0ZXN0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgQnJldXNjaC1QYWdhbiBUZXN0CmJwdGVzdChPTFMsIHN0dWRlbnRpemU9RkFMU0UpCgojIEtvZW5rZXItQmFzc2V0dCBUZXN0CmJwdGVzdChPTFMpIAoKIyBXaGl0ZSBUZXN0CndoaXRlX3Rlc3QoT0xTKQoKCmBgYAoKQ29tcGFyaW5nIHRvIHRoZSBzY2F0dGVyIHBsb3Qgd2UgbWFkZSB0byBpZGVudGlmeSBoZXRlcm9zY2VkYXN0aWNpdHkgZnJvbSB0aGUgcHJldmlvdXMgYXNzaWdubWVudCwgdGhlIHJlc2lkdWFscyBpbiB0aGlzIHNjYXR0ZXIgcGxvdCBzaG93IG5vIGRpc2Nlcm5pYmxlIHRyZW5kIG9mIHJpc2luZyBvciBmYWxsaW5nIHZhcmlhbmNlIHdpdGggaW5jcmVhc2luZyBmaXR0ZWQgdmFsdWVzOyBpbnN0ZWFkLCB0aGV5IHNlZW0gdG8gYmUgcHJldHR5IHVuaWZvcm1seSBkaXN0cmlidXRlZCBhcm91bmQgdGhlIGhvcml6b250YWwgbGluZSBhdCB6ZXJvLiBSZWdhcmRsZXNzLCB0aGUgQnJldXNjaC1QYWdhbiB0ZXN0IGlzIG9mdGVuIG1vcmUgc2Vuc2l0aXZlIHRoYW4gYSByZXNpZHVhbCBwbG90LiBFdmVuIHNtYWxsIGRldmlhdGlvbnMgdGhhdCBhcmUgaGFyZCB0byBzZWUgdmlzdWFsbHkgbWF5IGJlIGRldGVjdGVkLgoKCmBgYHtyIGhldGVyb3NjZWRhc3RpY2l0eSBwbG90LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZ2dwbG90KHJlZ0RhdGEsIGFlcyh4ID0gRml0dGVkLCB5ID0gU3RhbmRhcmRpemVkX1Jlc2lkdWFscykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyODNkM2IiLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuNikgKyAgICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICIjYzQ0NTM2Iiwgc2l6ZSA9IDEpICsgICAjCiAgbGFicygKICAgIHRpdGxlID0gIlNjYXR0ZXIgUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIHZzIEZpdHRlZCBWYWx1ZXMiLAogICAgeCA9ICJGaXR0ZWQgVmFsdWVzIiwKICAgIHkgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIKICApICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKYGBgCgpUaGUgcmVzdWx0cyBvZiB0aGUgSmFycXVlLUJlcmEgdGVzdCBpbmRpY2F0ZSBhIHNpZ25pZmljYW50IGRldmlhdGlvbiBmcm9tIG5vcm1hbGl0eSBpbiB0aGUgcmVzaWR1YWxzLiBUaGUgcC12YWx1ZSBpcyB3ZWxsIGJlbG93IHR5cGljYWwgc2lnbmlmaWNhbmNlIGxldmVscywgYW5kIHJlamVjdHMgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBUaGVyZWZvcmUsIHRoZSB0ZXN0IHJlc3VsdHMgc3VnZ2VzdCB0aGF0IHRoZSByZXNpZHVhbHMgZG8gbm90IG1lZXQgdGhlIG5vcm1hbGl0eSBhc3N1bXB0aW9uIHJlcXVpcmVkIGZvciBPTFMgcmVncmVzc2lvbi4KCmBgYHtyIG5vcm1hbGl0eSBvZiBlcnJvcnMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIEphcnF1ZS1CZXJhIFRlc3QgCmphcnF1ZS5iZXJhLnRlc3QoT0xTJHJlc2lkdWFscykKCmBgYAoKQ29tcGFyaW5nIHRvIHRoZSBoaXN0b2dyYW0gb2Ygc3RhbmRhcmRpemVkIHJlc2lkdWFscyBmcm9tIHRoZSBwcmV2aW91cyBhc3NpZ25tZW50LCB3ZSBtYXkgYWxzbyBub3RpY2UgdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSBub3QgcGVyZmVjdGx5IG5vcm1hbC4gVGhlIGhpc3RvZ3JhbSByZXZlYWxzIGEgc2xpZ2h0IGRlcGFydHVyZSBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhbmQgaXMgbGVmdCBza2V3ZWQuIERlc3BpdGUgdGhhdCB0aGUgc2tld25lc3MgaXMgbm90IHZlcnkgcHJvbm91bmNlZCwgaXQgaXMgc3RpbGwgY29uc2lzdGVudCB3aXRoIHRoZSBKYXJxdWUtQmVyYSB0ZXN0IHJlc3VsdHMuIAoKCmBgYHtyIGhpc3RvZ3JhbSBvZiByZXNpZHVhbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnZ3Bsb3QocmVnRGF0YSwgYWVzKHggPSBTdGFuZGFyZGl6ZWRfUmVzaWR1YWxzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICIjMjgzZDNiIiwgYWxwaGEgPSAwLjkpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgCiAgICAgICB4ID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCAKICAgICAgIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQpgYGAKClRoZSBzY2F0dGVycGxvdCBiZWxvdyBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgb2YgdGhlIE9MUyBtb2RlbCBhbmQgdGhlIHJlc2lkdWFscyBvZiB0aGVpciBuZWFyZXN0IG5laWdoYm9ycy4gVGhlIHVwd2FyZC1zbG9waW5nIHRyZW5kIGxpbmUgaW5kaWNhdGVzIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlc2UgcmVzaWR1YWxzIGFuZCB0aGVpciBuZWlnaGJvcnMsIHN1Z2dlc3Rpbmcgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIFRoZSBjb2VmZmljaWVudCBmb3IgdGhlIHJlc2lkdWFscyBvZiB0aGVpciBuZWFyZXN0IG5laWdoYm9ycyBpcyAwLjczMjMsIHdpdGggYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSwgZGVtb25zdHJhdGluZyBhIHN0cm9uZyBwb3NpdGl2ZSByZWxhdGlvbnNoaXAuIFRoaXMgaW1wbGllcyB0aGF0IHJlc2lkdWFscyBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggdGhvc2Ugb2YgdGhlaXIgY2xvc2VzdCBuZWlnaGJvcnMsIGltcGx5aW5nIHNwYXRpYWwgZGVwZW5kZW5jZS4KCmBgYHtyIG9scyByZXNpZHVhbHMgdnMgbmVhcmVzdCBuZWlnaGJvciByZXNpZHVhbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgpyZXMubG0gPC0gbG0oU3RhbmRhcmRpemVkX1Jlc2lkdWFscyB+IFJlc2lkdWFsc19OQiwgZGF0YT1yZWdEYXRhKQpzdW1tYXJ5KHJlcy5sbSkKCmBgYAoKCmBgYHtyIG9scyByZXNpZHVhbHMgdnMgbmVhcmVzdCBuZWlnaGJvciByZXNpZHVhbHMgcGxvdCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KHJlZ0RhdGEsIGFlcyh4ID0gUmVzaWR1YWxzX05CLCB5ID0gU3RhbmRhcmRpemVkX1Jlc2lkdWFscykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyODNkM2IiLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNjNDQ1MzYiLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiUmVzaWR1YWxzIHZzLiBOZWFyZXN0IE5laWdoYm9yIFJlc2lkdWFscyIsCiAgICAgICB4ID0gIk5lYXJlc3QgTmVpZ2hib3IgUmVzaWR1YWxzIiwKICAgICAgIHkgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKYGBgCgpUaGUgTW9yYW7igJlzIEkgc2NhdHRlcnBsb3QgYW5kIHRoZSByZXN1bHRzIGZyb20gdGhlIHBlcm11dGF0aW9ucyBmb3IgT0xTIHJlZ3Jlc3Npb24gcmVzaWR1YWxzIGJvdGggaW5kaWNhdGUgc2lnbmlmaWNhbnQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIFRoZSBzY2F0dGVycGxvdCBzaG93cyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBsb2dnZWQgbWVkaWFuIGhvdXNlIHZhbHVlcyBhbmQgdGhlaXIgc3BhdGlhbGx5IGxhZ2dlZCB2YWx1ZXMsIHdpdGggYSBwb3NpdGl2ZSBzbG9wZSwgY29uZmlybWluZyB0aGF0IGhpZ2ggdmFsdWVzIHRlbmQgdG8gYmUgbmVhciBvdGhlciBoaWdoIHZhbHVlcywgYW5kIGxvdyB2YWx1ZXMgY2x1c3RlciB3aXRoIG90aGVyIGxvdyB2YWx1ZXMuIFRoZSBNb3JhbidzIEkgc3RhdGlzdGljIGZyb20gdGhlIE1vbnRlIENhcmxvIHNpbXVsYXRpb24gaXMgYXBwcm94aW1hdGVseSAwLjMsIHdpdGggYW4gZXh0cmVtZWx5IGxvdyBwLXZhbHVlLCBjb25maXJtaW5nIHRoYXQgdGhpcyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LgoKVGhpcyBzaWduaWZpY2FudCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgT0xTIHJlc2lkdWFscyBpcyBwcm9ibGVtYXRpYyBiZWNhdXNlIGl0IHZpb2xhdGVzIHRoZSBPTFMgYXNzdW1wdGlvbiBvZiBpbmRlcGVuZGVudCByZXNpZHVhbHMuIFdoZW4gcmVzaWR1YWxzIGFyZSBzcGF0aWFsbHkgYXV0b2NvcnJlbGF0ZWQsIGl0IHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIGlzIG1pc3Npbmcgc3BhdGlhbCBzdHJ1Y3R1cmUgaW4gdGhlIGRhdGEsIHdoaWNoIGNvdWxkIGxlYWQgdG8gYmlhc2VkIG9yIGluZWZmaWNpZW50IGVzdGltYXRlcy4KCgpgYGB7ciBtb3JhbiBJIG9mIE9MUyByZXNpZHVhbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpPTFNfbW9yYW5NQzwtbW9yYW4ubWMoc3RhbmRhcmRpemVkX3Jlc2lkdWFscywgcXVlZW5saXN0LCBuc2ltPTk5OSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIpIApPTFNfbW9yYW5NQwoKYGBgCkJvdGggdGhlIE1vcmFu4oCZcyBJIHN0YXRpc3RpYyBhbmQgdGhlIHBvc2l0aXZlIGJldGEgY29lZmZpY2llbnQgZnJvbSB0aGUgcmVncmVzc2lvbiBvZiBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIG9uIHRoZWlyIG5lYXJlc3QgbmVpZ2hib3JzIHRlbGwgYSBzaW1pbGFyIHN0b3J5LiBUaGV5IGJvdGggcmV2ZWFsIHRoYXQgc3BhdGlhbCBkZXBlbmRlbmNlIGlzIHByZXNlbnQgaW4gdGhlIHJlc2lkdWFscywgc3VnZ2VzdGluZyB0aGF0IGEgc3BhdGlhbCBtb2RlbCwgc3VjaCBhcyBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uIChHV1IpIG9yIGEgc3BhdGlhbCBhdXRvcmVncmVzc2l2ZSBtb2RlbCwgd291bGQgYmUgbW9yZSBhcHByb3ByaWF0ZSBmb3IgY2FwdHVyaW5nIHRoZSB1bmRlcmx5aW5nIHNwYXRpYWwgcmVsYXRpb25zaGlwcyBpbiB0aGUgZGF0YS4KCgpgYGB7ciBtb3JhbiBJIG9mIE9MUyByZXNpZHVhbHMgaGlzdG9ncmFtIGFuZCBzY2F0dGVycGxvdCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcGx0MSA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShyZXMgPSBPTFNfbW9yYW5NQyRyZXMpLCBhZXMoeCA9IHJlcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsID0gIiMyODNkM2IiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID1PTFNfbW9yYW5NQyRzdGF0aXN0aWMsIGNvbG9yID0gIiNjNDQ1MzYiLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiT2JzZXJ2ZWQgYW5kIFBlcm11dGVkIE1vcmFuJ3MgSSBvZiBPTFMgUmVzaWR1YWxzIiwKICAgICAgIHN1YnRpdGxlID0gIk9ic2VydmVkIE1vcmFuJ3MgSSBpbiBSZWQiLAogICAgICAgeCA9ICJNb3JhbidzIEkiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKCnBsdDIgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIHJlc2lkdWFscyA9c3RhbmRhcmRpemVkX3Jlc2lkdWFscywKICBzcGF0aWFsX2xhZyA9IGxhZy5saXN0dyhxdWVlbmxpc3QsIHN0YW5kYXJkaXplZF9yZXNpZHVhbHMpCiksIGFlcyh4ID0gcmVzaWR1YWxzLCB5ID0gc3BhdGlhbF9sYWcpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMjgzZDNiIiwgYWxwaGEgPSAwLjksIHNpemUgPSAwLjYpICsgIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gIiNjNDQ1MzYiLCBzZSA9IEZBTFNFKSArIAogIGxhYnModGl0bGUgPSAiTW9yYW4ncyBJIFNjYXR0ZXIgUGxvdCBmb3IgT0xTIFJlc2lkdWFscyIsCiAgICAgICB4ID0gIkxvZ2dlZCBNZWRpYW4gSG91c2UgVmFsdWUiLAogICAgICAgeSA9ICJTcGF0aWFsIExhZyBvZiBMTk1FREhWQUwiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpwbHQxICsgcGx0MgpgYGAKCgojIyBTcGF0aWFsIExhZyBhbmQgRXJyb3IgUmVncmVzc2lvbiBSZXN1bHRzCgojIyMgU3BhdGlhbCBMYWcgUmVncmVzc2lvbgoKSW4gdGhlIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24gb3V0cHV0LCB3ZSBtYXkgc2VlIHRoYXQgdGhlIHRlcm0gXChcdGV4dHtMTk1FREhWQUx9XCksIHJlcHJlc2VudGVkIGJ5IFwoIFxyaG8gXCkgaW4gdGhlIG1vZGVsLCBoYXMgYW4gZXN0aW1hdGUgb2YgMC42NTEgYW5kIGFuIGV4dHJlbWVseSBzaWduaWZpY2FudCBwLXZhbHVlIChcKCBwIDwgMi4yMiBcdGltZXMgMTBeey0xNn0gXCkpLlRoaXMgaW5kaWNhdGVzIHRoYXQgbmVhcmJ5IHZhbHVlcyBvZiB0aGUgZGVwZW5kZW50IHZhbHVlIGluZmx1ZW5jZSBlYWNoIG90aGVyLiBUaGUgc2lnbmlmaWNhbnQgcG9zaXRpdmUgY29lZmZpY2llbnQgKFwoIFxyaG8gPSAwLjY1MSBcKSkgc3VnZ2VzdHMgYSBzdWJzdGFudGlhbCBwb3NpdGl2ZSBzcGF0aWFsIGxhZyBlZmZlY3QsIG1lYW5pbmcgdGhhdCBoaWdoZXIgbWVkaWFuIGhvbWUgdmFsdWVzIGluIG5laWdoYm9yaW5nIGFyZWFzIGFyZSBhc3NvY2lhdGVkIHdpdGggaGlnaGVyIG1lZGlhbiBob21lIHZhbHVlcyBpbiB0aGUgYXJlYSBiZWluZyBleGFtaW5lZC4KCkFsbCBwcmVkaWN0b3JzIGluIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBhcmUgc2lnbmlmaWNhbnQuIFwoXHRleHR7UENUVkFDQU5UfVwpIGhhcyBhIGNvZWZmaWNpZW50IG9mIC0wLjAwODUgYW5kIGlzIGhpZ2hseSBzaWduaWZpY2FudCBzaW5jZSBcKCBwIDwgMi4yMiBcdGltZXMgMTBeey0xNn0gXCkuIEl0IG1lYW5zIGEgaGlnaGVyIHZhY2FuY3kgcmF0ZSBpcyBhc3NvY2lhdGVkIHdpdGggbG93ZXIgbWVkaWFuIGhvbWUgdmFsdWVzLiBcKFx0ZXh0e1BDVFNJTkdMRVN9XCkgaGFzIGEgY29lZmZpY2llbnQgb2YgMC4wMDIwLCBzaWduaWZpY2FudCB3aXRoIGEgXCggcCA8IDAuMDAwMSBcKS4gVGhlIHBvc2l0aXZlIGFzc29jaWF0aW9uIHN1Z2dlc3RzIHRoYXQgYXJlYXMgd2l0aCBhIGhpZ2hlciBwcm9wb3J0aW9uIG9mIHNpbmdsZSBob3VzZWhvbGRzIG1heSBzbGlnaHRseSBpbmNyZWFzZSBtZWRpYW4gaG9tZSB2YWx1ZXMuIFwoXHRleHR7UENUQkFDSE1PUn1cKSBoYXMgYSBjb2VmZmljaWVudCBvZiAwLjAwODUgYW5kIGlzIGV4dHJlbWVseSBzaWduaWZpY2FudCAoXCggcCA8IDIuMjIgXHRpbWVzIDEwXnstMTZ9IFwpKS4gSGlnaGVyIGVkdWNhdGlvbiBsZXZlbHMgYXJlIHBvc2l0aXZlbHkgYXNzb2NpYXRlZCB3aXRoIGhvbWUgdmFsdWVzLCBtZWFuaW5nIHRoYXQgbW9yZSBlZHVjYXRlZCBhcmVhcyB0ZW5kIHRvIGhhdmUgaGlnaGVyIGhvbWUgdmFsdWVzLiBcKFx0ZXh0e0xOTkJFTFBPVn1cKSBoYXMgYSBjb2VmZmljaWVudCBvZiAtMC4wMzQxLCBhbHNvIGhpZ2hseSBzaWduaWZpY2FudCAoXCggcCA8IDEgXHRpbWVzIDEwXnstN30gXCkpLiBUaGUgbmVnYXRpdmUgYXNzb2NpYXRpb24gc3VnZ2VzdHMgdGhhdCBoaWdoZXIgcG92ZXJ0eSBsZXZlbHMgYXJlIGFzc29jaWF0ZWQgd2l0aCBsb3dlciBtZWRpYW4gaG9tZSB2YWx1ZXMuCgpUaGUgT0xTIG1vZGVsIGFsc28gc2hvd3Mgc2lnbmlmaWNhbnQgY29lZmZpY2llbnRzIGZvciBhbGwgcHJlZGljdG9ycywgYnV0IHdpdGggbGFyZ2VyIGVmZmVjdCBzaXplcy4gRm9yIGV4YW1wbGUsIFx0ZXh0e1BDVFZBQ0FOVH0gaGFzIGEgY29lZmZpY2llbnQgb2YgLTAuMDE5MiBpbiBPTFMsIGNvbXBhcmVkIHRvIC0wLjAwODUgaW4gc3BhdGlhbCBsYWcuIFRoaXMgc3VnZ2VzdHMgdGhhdCBPTFMgb3ZlcmVzdGltYXRlcyB0aGUgaW5mbHVlbmNlIG9mIHRoZXNlIHByZWRpY3RvcnMgZHVlIHRvIG9taXR0ZWQgc3BhdGlhbCBkZXBlbmRlbmNlLiBGb3IgdGhlIG90aGVyIHByZWRpY3RvcnMsIHRoZSBPTFMgY29lZmZpY2llbnRzIGFyZSBhbHNvIGxhcmdlciBpbiBtYWduaXR1ZGUgdGhhbiB0aGUgc3BhdGlhbCBsYWcgY29lZmZpY2llbnRzLiAKCmBgYHtyIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpTTCA8LSBsYWdzYXJsbShMTk1FREhWQUwgfiBQQ1RWQUNBTlQgKyBQQ1RTSU5HTEVTICsgUENUQkFDSE1PUiArIExOTkJFTFBPViwgZGF0YT1yZWdEYXRhLCBxdWVlbmxpc3QpCnN1bW1hcnkoU0wpCgpgYGAKCldlIHJhbiBCcmV1c2NoLVBhZ2FuIHRlc3QgdG8gYXNzZXNzIHdoZXRoZXIgdGhlIHJlc2lkdWFscyBvZiB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBtb2RlbCBleGhpYml0IGhldGVyb3NjZWRhc3RpY2l0eS4gQXMgd2UgbWF5IHNlZSwgdGhlIHRlc3Qgc3RhdGlzdGljIGZvciB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBpcyBcKCBCUCA9IDIxMSBcKSB3aXRoIFwoIGRmID0gNCBcKSwgYW5kIFwoIHAgPCAyIFx0aW1lcyAxMF57LTE2fSBcKS4gR2l2ZW4gdGhlIGV4dHJlbWVseSBsb3cgcC12YWx1ZSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgb2YgaG9tb3NjZWRhc3RpY2l0eSwgaW5kaWNhdGluZyB0aGF0IHJlc2lkdWFscyBpbiB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBtb2RlbCByZW1haW4gaGV0ZXJvc2NlZGFzdGljLgoKCmBgYHtyIFNMIGhldGVyb3NjZWRhc3RpY2l0eSB0ZXN0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgQnJldXNjaC1QYWdhbiBUZXN0CmJwdGVzdC5TYXJsbShTTCwgc3R1ZGVudGl6ZT1GQUxTRSkKCmBgYAoKV2hlbiBjb21wYXJpbmcgdGhlIE9MUyBhbmQgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBtb2RlbHMsIHNldmVyYWwgbWV0cmljcyBzaG93IHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBwcm92aWRlcyBhIGJldHRlciBmaXQuIFRoZSBzcGF0aWFsIGxhZyBtb2RlbCBoYXMgYSBzaWduaWZpY2FudGx5IGxvd2VyIEFJQyAoNTI1KSB0aGFuIE9MUyAoMTQzNSksIGluZGljYXRpbmcgYSBiZXR0ZXIgbW9kZWwgZml0IGJ5IHBlbmFsaXppbmcgbGVzcyBmb3IgYWRkZWQgY29tcGxleGl0eS4gU2ltaWxhcmx5LCB0aGUgU2Nod2FyeiBDcml0ZXJpb24gaXMgbXVjaCBsb3dlciBmb3IgdGhlIHNwYXRpYWwgbGFnIG1vZGVsLCBzdWdnZXN0aW5nIGl0IGNhcHR1cmVzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgbW9yZSBlZmZlY3RpdmVseSB0aGFuIHRoZSBPTFMgbW9kZWwuIFRoZSBzcGF0aWFsIGxhZyBtb2RlbCAoLTI1NikgaGFzIGEgaGlnaGVyIGxvZyBsaWtlbGlob29kIHRoYW4gT0xTICgtNzExKSwgbWVhbmluZyB0aGF0IGl0IGJldHRlciBleHBsYWlucyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEuCgpgYGB7ciBjb21wYXJlIE9MUyBhbmQgU0wsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24KYWljX29scyA8LSBBSUMoT0xTKQphaWNfc2wgPC0gQUlDKFNMKQoKIyBTY2h3YXJ6IENyaXRlcmlvbgpiaWNfb2xzIDwtIEJJQyhPTFMpCmJpY19zbCA8LSBCSUMoU0wpCgojIFRoZSBMb2cgTGlrZWxpaG9vZApsb2dsaWtfb2xzIDwtIGxvZ0xpayhPTFMpCmxvZ2xpa19zbCA8LSBsb2dMaWsoU0wpCgpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgTW9kZWwgPSBjKCJPTFMgUmVncmVzc2lvbiIsICJTcGF0aWFsIExhZyBSZWdyZXNzaW9uIiksCiAgQUlDID0gYyhhaWNfb2xzLCBhaWNfc2wpLAogIFNjaHdhcnpDcml0ZXJpb24gPSBjKGJpY19vbHMsIGJpY19zbCksCiAgTG9nTGlrZWxpaG9vZCA9IGMobG9nbGlrX29scywgbG9nbGlrX3NsKQopCgpyZXN1bHRzICU+JQogIGthYmxlKHJvdy5uYW1lcyA9IEZBTFNFKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSkgCgoKYGBgCgpUaGUgTGlrZWxpaG9vZCBSYXRpbyBUZXN0IGFzc2Vzc2VzIHRoZSBpbXByb3ZlbWVudCBpbiBtb2RlbCBmaXQgYmV0d2VlbiB0aGUgT0xTIGFuZCBzcGF0aWFsIGxhZyBtb2RlbHMsIGFuZCB0aGUgcmVzdWx0IHdlIGdldCBoZXJlIHNob3dzIFwoIExSID0gOTEyIFwpIHdpdGggXCggZGYgPSAxIFwpLCBhbmQgXCggcCA8IDIgXHRpbWVzIDEwXnstMTZ9IFwpLiBXaXRoIGEgbGFyZ2UgdGVzdCBzdGF0aXN0aWMgYW5kIGxvdyBwLXZhbHVlLCB3ZSBjb25jbHVkZSB0aGF0IHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBzaWduaWZpY2FudGx5IGltcHJvdmVzIGZpdCBvdmVyIHRoZSBPTFMgbW9kZWwuIAoKYGBge3IgbG9nIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBmb3IgU0wsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIFRoZSBMaWtlbGlob29kIFJhdGlvIFRlc3QKbHJfdGVzdCA8LSBMUi5TYXJsbShTTCwgT0xTKQpscl90ZXN0CgpgYGAKCkZpbmFsbHksIHdlIGV4YW1pbmVkIE1vcmFuJ3MgSSBmb3IgdGhlIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24gbW9kZWwncyByZXNpZHVhbHMuVGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIG9mIC0wLjA4IHN1Z2dlc3RzIGEgc21hbGwgbmVnYXRpdmUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlc2lkdWFscyBvZiB0aGUgc3BhdGlhbCBsYWcgbW9kZWwuIFdpdGggXCggcCA9IDAuMDAyIFwpLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVGhpcyBuZWdhdGl2ZSBNb3JhbuKAmXMgSSBpbmRpY2F0ZXMgdGhhdCByZXNpZHVhbHMgYXJlIGRpc3RyaWJ1dGVkIHdpdGggc2xpZ2h0IHNwYXRpYWwgZGlzcGVyc2lvbiByYXRoZXIgdGhhbiBjbHVzdGVyaW5nLCBzdWdnZXN0aW5nIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBlZmZlY3RpdmVseSBhY2NvdW50cyBmb3IgbW9zdCBzcGF0aWFsIGRlcGVuZGVuY2llcyBpbiB0aGUgZGF0YS4KCmBgYHtyIG1vcmFuIEkgb2YgU0wgcmVzaWR1YWxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKU0xfbW9yYW5NYzwtbW9yYW4ubWMoU0wkcmVzaWR1YWxzLCBxdWVlbmxpc3QsOTk5LCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIikKU0xfbW9yYW5NYwoKYGBgCgpCb3RoIHRoZSByZXNpZHVhbCBoaXN0b2dyYW1zIGFzIHdlbGwgYXMgdGhlIHNjYXR0ZXIgcGxvdCBzdXBwb3J0IHRoaXMgY29uY2x1c2lvbi4gVGhlIGhpc3RvZ3JhbSBvZiByZXNpZHVhbHMgaXMgYWxzbyBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBhbmQgdGhlIHNjYXR0ZXIgcGxvdCBvZiByZXNpZHVhbHMgYWdhaW5zdCBmaXR0ZWQgdmFsdWVzIHNob3dzIG5vIGNsZWFyIHBhdHRlcm4gb3IgdHJlbmQuIEFsbCBvZiB0aGVzZSBzdWdnZXN0IHRoYXQgdGhlIHNwYXRpYWwgbGFnIG1vZGVsIGlzIGEgZ29vZCBmaXQgZm9yIHRoZSBkYXRhIGNvbXBhcmVkIHRvIE9MUy4gCgpgYGB7ciBtb3JhbiBJIG9mIFNMIHJlc2lkdWFscyBoaXN0b2dyYW0gYW5kIHNjYXR0ZXJwbG90LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbHQzIDwtIGdncGxvdChkYXRhLmZyYW1lKHJlcyA9IFNMJHJlc2lkdWFscyksIGFlcyh4ID0gcmVzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDAsIGZpbGwgPSAiIzI4M2QzYiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPVNMX21vcmFuTWMkc3RhdGlzdGljLCBjb2xvciA9ICIjYzQ0NTM2IiwgbGluZXR5cGUgPSAnZGFzaGVkJywgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIk9ic2VydmVkIGFuZCBQZXJtdXRlZCBNb3JhbidzIEkgb2YgU0wgUmVzaWR1YWxzIiwKICAgICAgIHN1YnRpdGxlID0gIk9ic2VydmVkIE1vcmFuJ3MgSSBpbiBSZWQiLAogICAgICAgeCA9ICJNb3JhbidzIEkiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKCnBsdDQgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIHJlc2lkdWFscyA9U0wkcmVzaWR1YWxzLAogIHNwYXRpYWxfbGFnID0gbGFnLmxpc3R3KHF1ZWVubGlzdCwgU0wkcmVzaWR1YWxzKQopLCBhZXMoeCA9IHJlc2lkdWFscywgeSA9IHNwYXRpYWxfbGFnKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzI4M2QzYiIsIGFscGhhID0gMC45LCBzaXplID0gMC42KSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICIjYzQ0NTM2Iiwgc2UgPSBGQUxTRSkgKyAKICBsYWJzKHRpdGxlID0gIk1vcmFuJ3MgSSBTY2F0dGVyIFBsb3QgZm9yIFNMIFJlc2lkdWFscyIsCiAgICAgICB4ID0gIkxvZ2dlZCBNZWRpYW4gSG91c2UgVmFsdWUiLAogICAgICAgeSA9ICJTcGF0aWFsIExhZyBvZiBMTk1FREhWQUwiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpwbHQzICsgcGx0NApgYGAKCgojIyMgU3BhdGlhbCBFcnJvciBSZWdyZXNzaW9uCgpJbiB0aGUgc3BhdGlhbCBlcnJvciByZWdyZXNzaW9uIG1vZGVsLCB0aGUgdGVybSBcKFxsYW1iZGFcKSByZXByZXNlbnRzIHRoZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiB3aXRoaW4gdGhlIG1vZGVs4oCZcyBlcnJvciB0ZXJtcy4gSW4gdGhpcyBjYXNlLCBcKFxsYW1iZGFcKSBpcyBlc3RpbWF0ZWQgYXQgMC44MTUgYW5kIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHdpdGggXCggcCA8IDIuMjIgXHRpbWVzIDEwXnstMTZ9IFwpLiBUaGlzIGhpZ2hseSBzaWduaWZpY2FudCBhbmQgbGFyZ2UgdmFsdWUgb2YgXChcbGFtYmRhXCkgc3VnZ2VzdHMgYSBzdHJvbmcgc3BhdGlhbCBkZXBlbmRlbmN5IGluIHRoZSBlcnJvciB0ZXJtcy4gCgpFeGFtaW5pbmcgdGhlIGluZGl2aWR1YWwgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwsIGFsbCB2YXJpYWJsZXMgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYXQgYSBoaWdoIGNvbmZpZGVuY2UgbGV2ZWwuIFwoXHRleHR7UENUVkFDQU5UfVwpIGhhcyBhbiBlc3RpbWF0ZSBvZiAtMC4wMDU4IChcKCBwIDwgNi45NCBcdGltZXMgMTBeey05fSBcKSksIGluZGljYXRpbmcgdGhhdCB2YWNhbmN5IHJhdGVzIG5lZ2F0aXZlbHkgYWZmZWN0IG1lZGlhbiBob21lIHZhbHVlcy4gXChcdGV4dHtQQ1RTSU5HTEVTfVwpIGhhcyBhIHBvc2l0aXZlIGNvZWZmaWNpZW50IG9mIDAuMDAyNyAoXCggcCA8IDEuNjEgXHRpbWVzIDEwXnstNX0gXCkpLCBzdWdnZXN0aW5nIGEgc21hbGwgcG9zaXRpdmUgYXNzb2NpYXRpb24gd2l0aCBtZWRpYW4gaG9tZSB2YWx1ZXMuIFwoXHRleHR7UENUQkFDSE1PUn1cKSAsIHJlcHJlc2VudGluZyB0aGUgcGVyY2VudGFnZSBvZiBiYWNoZWxvcuKAmXMgZGVncmVlcyBvciBoaWdoZXIsIHNob3dzIGEgcG9zaXRpdmUgZWZmZWN0IHdpdGggYW4gZXN0aW1hdGUgb2YgMC4wMDk4IChcKCBwIDwgMi4yMCBcdGltZXMgMTBeey0xNn0gXCkpLCBpbmRpY2F0aW5nIHRoYXQgaGlnaGVyIGVkdWNhdGlvbiBsZXZlbHMgY29ycmVsYXRlIHdpdGggaGlnaGVyIGhvbWUgdmFsdWVzLiBcKFx0ZXh0e0xOTkJFTFBPVn1cKSBoYXMgYSBuZWdhdGl2ZSBlc3RpbWF0ZSBvZiAtMC4wMzQ1IGFuZCBcKCBwIDwgMS4xMSBcdGltZXMgMTBeey02fSBcKSwgaW1wbHlpbmcgdGhhdCBoaWdoZXIgbGV2ZWxzIG9mIG5laWdoYm9yaG9vZCBwb3ZlcnR5IGFyZSBhc3NvY2lhdGVkIHdpdGggbG93ZXIgbWVkaWFuIGhvbWUgdmFsdWVzLgoKU2ltaWxhciB0byBzcGF0aWFsIGxhZyByZWdyZXNzaW9uLCB3aGVuIGNvbXBhcmluZyB0aGVzZSByZXN1bHRzIHdpdGggdGhlIE9MUyByZWdyZXNzaW9uIG1vZGVsLCB3ZSBvYnNlcnZlIHRoYXQgdGhlIGNvZWZmaWNpZW50cyBmb3Igb3VyIHByZWRpY3RvcnMgYXJlIGFsbCBzbWFsbGVyIGluIG1hZ25pdHVkZSB0aGFuIHRoZWlyIE9MUyBjb3VudGVycGFydHMuIEZvciBpbnN0YW5jZSwgXHRleHR7UENUVkFDQU5UfSBoYWQgYSBjb2VmZmljaWVudCBvZiAtMC4wMTkxNTYgaW4gdGhlIE9MUyBtb2RlbCwgd2hpbGUgaW4gdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwsIGl0IGlzIHJlZHVjZWQgdG8gLTAuMDA1OC4gVGhpcyByZWR1Y3Rpb24gaW4gY29lZmZpY2llbnQgbWFnbml0dWRlIHN1Z2dlc3RzIHRoYXQgdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgcHJvdmlkZXMgYSBtb3JlIGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZSBvZiB0aGUgZWZmZWN0cyBvZiB0aGVzZSBwcmVkaWN0b3JzIG9uIG1lZGlhbiBob21lIHZhbHVlcywgbGlrZWx5IGR1ZSB0byB0aGUgYWNjb3VudGVkIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLgoKCmBgYHtyIHNwYXRpYWwgZXJyb3IgcmVncmVzc2lvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KClNFIDwtIGVycm9yc2FybG0oTE5NRURIVkFMIH4gUENUVkFDQU5UICsgUENUU0lOR0xFUyArIFBDVEJBQ0hNT1IgKyBMTk5CRUxQT1YsIGRhdGE9cmVnRGF0YSwgcXVlZW5saXN0KQpzdW1tYXJ5KFNFKQoKYGBgCgpCYXNlZCBvbiB0aGUgcmVzdWx0cyBvZiB0aGUgQnJldXNjaC1QYWdhbiB0ZXN0LCB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiByZXNpZHVhbHMgYXJlIGluZGVlZCBoZXRlcm9zY2VkYXN0aWMuIFRoZSB0ZXN0IHN0YXRpc3RpYyBpcyBcKCBCUCA9IDIzIFwpIHdpdGggXCggZGYgPSA0IFwpLCBhbmQgXCggcCA8IDAuMDAwMSBcKS4gU2luY2UgdGhlIHAtdmFsdWUgaXMgc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIHRoZSBjb252ZW50aW9uYWwgYWxwaGEgbGV2ZWxzICgwLjAxLCAwLjA1KSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgb2YgaG9tb3NjZWRhc3RpY2l0eS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHJlc2lkdWFscyBpcyBub3QgY29uc3RhbnQgYWNyb3NzIG9ic2VydmF0aW9ucywgc3VnZ2VzdGluZyB0aGUgcHJlc2VuY2Ugb2YgaGV0ZXJvc2NlZGFzdGljaXR5IGluIHRoZSBtb2RlbCdzIHJlc2lkdWFscy4KCmBgYHtyIFNFIGhldGVyb3NjZWRhc3RpY2l0eSB0ZXN0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgQnJldXNjaC1QYWdhbiBUZXN0IApicHRlc3QuU2FybG0oU0UsIHN0dWRlbnRpemU9RkFMU0UpCgpgYGAKCldlIGFsc28gY29tcGFyZWQgdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgdG8gdGhlIE9MUyBtb2RlbCB1c2luZyB0aGUgQUlDLCBTQywgbG9nLWxpa2VsaWhvb2QsIGFuZCBsaWtlbGlob29kIHJhdGlvIHRlc3QuIFRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGhhcyBhIGxvd2VyIEFJQyAoNzU5KSBhbmQgU0MgKDc5OCkgdGhhbiB0aGUgT0xTIG1vZGVsICgxNDM1IGFuZCAxNDY4LCByZXNwZWN0aXZlbHkpLCBpbmRpY2F0aW5nIGEgYmV0dGVyIGZpdC4gVGhlIGxvZy1saWtlbGlob29kIG9mIHRoZSBzcGF0aWFsIGVycm9yIG1vZGVsICgtMzczKSBpcyBhbHNvIGhpZ2hlciB0aGFuIHRoYXQgb2YgdGhlIE9MUyBtb2RlbCAoLTcxMSksIHN1Z2dlc3RpbmcgdGhhdCB0aGUgc3BhdGlhbCBlcnJvciBtb2RlbCBiZXR0ZXIgZXhwbGFpbnMgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSBkYXRhLgoKYGBge3IgY29tcGFyZSBPTFMgU0wgYW5kIFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uCmFpY19zZSA8LSBBSUMoU0UpCgojIFNjaHdhcnogQ3JpdGVyaW9uCmJpY19zZSA8LSBCSUMoU0UpCgojIFRoZSBMb2cgTGlrZWxpaG9vZApsb2dsaWtfc2UgPC0gbG9nTGlrKFNFKQoKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIE1vZGVsID0gYygiT0xTIFJlZ3Jlc3Npb24iLCAiU3BhdGlhbCBMYWcgUmVncmVzc2lvbiIsICJTcGF0aWFsIEVycm9yIFJlZ3Jlc3Npb24iKSwKICBBSUMgPSBjKGFpY19vbHMsIGFpY19zbCwgYWljX3NlKSwKICBTY2h3YXJ6Q3JpdGVyaW9uID0gYyhiaWNfb2xzLCBiaWNfc2wsIGJpY19zZSksCiAgTG9nTGlrZWxpaG9vZCA9IGMobG9nbGlrX29scywgbG9nbGlrX3NsLCBsb2dsaWtfc2UpCikKCnJlc3VsdHMgJT4lCiAga2FibGUocm93Lm5hbWVzID0gRkFMU0UpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAKCgpgYGAKCkFjY29yZGluZyB0byB0aGUgTGlrZWxpaG9vZCBSYXRpbyBUZXN0LCB3ZSBzZWUgXCggTFIgPSA2NzggXCkgd2l0aCBcKCBkZiA9IDEgXCksIGFuZCBcKCBwIDwgMiBcdGltZXMgMTBeey0xNn0gXCkuIFdpdGggYSBsYXJnZSB0ZXN0IHN0YXRpc3RpYyBhbmQgbG93IHAtdmFsdWUsIHdlIG1heSBhbHNvIGNvbmNsdWRlIHRoYXQgdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgc2lnbmlmaWNhbnRseSBpbXByb3ZlcyBmaXQgb3ZlciB0aGUgT0xTIG1vZGVsLiAKCmBgYHtyIGxvZyBsaWtlbGlob29kIHJhdGlvIHRlc3QgZm9yIFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbHJfdGVzdCA8LSBMUi5TYXJsbShTRSwgT0xTKQpscl90ZXN0CgpgYGAKCkZpbmFsbHksIHdlIGV4YW1pbmVkIE1vcmFuJ3MgSSBmb3IgdGhlIHNwYXRpYWwgZXJyb3IgcmVncmVzc2lvbiBtb2RlbCdzIHJlc2lkdWFscy4gVGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIG9mIC0wLjA5IHN1Z2dlc3RzIGEgc21hbGwgbmVnYXRpdmUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlc2lkdWFscyBvZiB0aGUgc3BhdGlhbCBlcnJvciBtb2RlbC4gCldpdGggXCggcCA9IDAuMDAyIFwpLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVGhpcyBuZWdhdGl2ZSBNb3JhbuKAmXMgSSBpbmRpY2F0ZXMgdGhhdCByZXNpZHVhbHMgYXJlIGRpc3RyaWJ1dGVkIHdpdGggc2xpZ2h0IHNwYXRpYWwgZGlzcGVyc2lvbiByYXRoZXIgdGhhbiBjbHVzdGVyaW5nLCBzdWdnZXN0aW5nIHRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGVmZmVjdGl2ZWx5IGFjY291bnRzIGZvciBtb3N0IHNwYXRpYWwgZGVwZW5kZW5jaWVzIGluIHRoZSBkYXRhLgoKCmBgYHtyIG1vcmFuIEkgb2YgU0UgcmVzaWR1YWxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKU0VfbW9yYW5NYzwtbW9yYW4ubWMocmVzaWR1YWxzKFNFKSwgcXVlZW5saXN0LDk5OSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIpClNFX21vcmFuTWMKCmBgYAoKQm90aCB0aGUgcmVzaWR1YWwgaGlzdG9ncmFtcyBhcyB3ZWxsIGFzIHRoZSBzY2F0dGVyIHBsb3Qgc3VwcG9ydCB0aGlzIGNvbmNsdXNpb24gaGVyZSBhZ2Fpbi4gVGhlIGhpc3RvZ3JhbSBvZiByZXNpZHVhbHMgaXMgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCwgYW5kIHRoZSBzY2F0dGVyIHBsb3Qgb2YgcmVzaWR1YWxzIGFnYWluc3QgZml0dGVkIHZhbHVlcyBzaG93cyBhIG11Y2ggbGVzcyBldmlkZW50IHRyZW5kIGNvbXBhcmVkIHRvIHRoZSBPTFMgbW9kZWwuIFRoZXJlZm9yZSwgYWxsIG9mIHRoZXNlIHN1Z2dlc3QgdGhhdCB0aGUgc3BhdGlhbCBlcnJvciBtb2RlbCBpcyBhIGdvb2QgZml0IGZvciB0aGUgZGF0YSBjb21wYXJlZCB0byBPTFMuCgpgYGB7ciBtb3JhbiBJIG9mIFNFIHJlc2lkdWFscyBoaXN0b2dyYW0gYW5kIHNjYXR0ZXJwbG90LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbHQ1IDwtIGdncGxvdChkYXRhLmZyYW1lKHJlcyA9IHJlc2lkdWFscyhTRSkpLCBhZXMoeCA9IHJlcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsID0gIiMyODNkM2IiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID1TRV9tb3Jhbk1jJHN0YXRpc3RpYywgY29sb3IgPSAiI2M0NDUzNiIsIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJPYnNlcnZlZCBhbmQgUGVybXV0ZWQgTW9yYW4ncyBJIG9mIFNFIFJlc2lkdWFscyIsCiAgICAgICBzdWJ0aXRsZSA9ICJPYnNlcnZlZCBNb3JhbidzIEkgaW4gUmVkIiwKICAgICAgIHggPSAiTW9yYW4ncyBJIiwKICAgICAgIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpwbHQ2IDwtIGdncGxvdChkYXRhID0gZGF0YS5mcmFtZSgKICByZXNpZHVhbHMgPSByZXNpZHVhbHMoU0UpLAogIHNwYXRpYWxfbGFnID0gbGFnLmxpc3R3KHF1ZWVubGlzdCwgcmVzaWR1YWxzKFNFKSkKKSwgYWVzKHggPSByZXNpZHVhbHMsIHkgPSBzcGF0aWFsX2xhZykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyODNkM2IiLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuNikgKyAgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiI2M0NDUzNiIsIHNlID0gRkFMU0UpICsgCiAgbGFicyh0aXRsZSA9ICJNb3JhbidzIEkgU2NhdHRlciBQbG90IGZvciBTRSBSZXNpZHVhbHMiLAogICAgICAgeCA9ICJMb2dnZWQgTWVkaWFuIEhvdXNlIFZhbHVlIiwKICAgICAgIHkgPSAiU3BhdGlhbCBMYWcgb2YgTE5NRURIVkFMIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQoKcGx0NSArIHBsdDYKYGBgCgpJdCBzaG91bGQgYmUgbm90ZWQgdGhhdCBoZXJlLCB3ZSBhbHNvIGNvbXBhcmVkIHNwYXRpYWwgbGFnIG1vZGVsIHdpdGggdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwuIFRoZSBzcGF0aWFsIGxhZyBtb2RlbCBoYXMgYSBsb3dlciBBSUMgKDUyNSkgYW5kIFNDICg1NjQpIHRoYW4gdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgKDc1OSBhbmQgNzk4LCByZXNwZWN0aXZlbHkpLCBpbmRpY2F0aW5nIGEgYmV0dGVyIGZpdC4gVGhlIGxvZy1saWtlbGlob29kIG9mIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCAoLTI1NikgaXMgYWxzbyBsZXNzIG5lZ2F0aXZlIHRoYW4gdGhhdCBvZiB0aGUgc3BhdGlhbCBsYWcgZXJyb3IgKC0zNzMpLCBzdWdnZXN0aW5nIHRoYXQgdGhlIHNwYXRpYWwgbGFnIG1vZGVsIGJldHRlciBleHBsYWlucyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEuIAoKIyMgR2VvZ3JhcGhpY2FsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbiBSZXN1bHRzCgpgYGB7ciBjb3ZlcnQgZmlsZSBzdHJ1Y3R1cmUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgpyZWdEYXRhc2hwcyA8LSBhcyhyZWdEYXRhLCAnU3BhdGlhbCcpICAKCmBgYAoKCmBgYHtyIGd3ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCmJ3PC1nd3Iuc2VsKGZvcm11bGE9TE5NRURIVkFMIH4gUENUVkFDQU5UICsgUENUU0lOR0xFUyArIFBDVEJBQ0hNT1IgKyBMTk5CRUxQT1YsIAogICAgICAgICAgICBkYXRhPXJlZ0RhdGFzaHBzLAogICAgICAgICAgICBtZXRob2QgPSAiYWljIiwKICAgICAgICAgICAgYWRhcHQgPSBUUlVFKQpnd3Jtb2RlbDwtZ3dyKGZvcm11bGE9TE5NRURIVkFMIH4gUENUVkFDQU5UICsgUENUU0lOR0xFUyArIFBDVEJBQ0hNT1IgKyBMTk5CRUxQT1YsCiAgICAgICAgICAgICAgZGF0YT1yZWdEYXRhc2hwcywKICAgICAgICAgICAgICBhZGFwdCA9IGJ3LCAjIGFkYXB0aXZlIGJhbmR3aWR0aAogICAgICAgICAgICAgIGd3ZWlnaHQ9Z3dyLkdhdXNzLAogICAgICAgICAgICAgIHNlLmZpdD1UUlVFLCAKICAgICAgICAgICAgICBoYXRtYXRyaXggPSBUUlVFKQpgYGAKCgpgYGB7ciBsb2FkIHByb2Nlc3NlZCBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKYncgPC0gcmVhZFJEUyhoZXJlKCJkYXRhIiwgImJhbmR3aWR0aF9nd3IucmRzIikpCmd3cm1vZGVsIDwtIHJlYWRSRFMoaGVyZSgiZGF0YSIsICJnd3Jtb2RlbC5yZHMiKSkKYGBgCgpUaGUgXChSXjJcKSBmb3IgdGhlIE9MUyByZWdyZXNzaW9uIG1vZGVsIGlzIDAuNjYyLCB3aGlsZSB0aGUgXChSXjJcKSAoUXVhc2ktZ2xvYmFsIFwoUl4yXCkgKSBmb3IgdGhlIEdXUiBtb2RlbCBpcyAwLjg0OC4gVGhlIGhpZ2hlciBcKFJeMlwpIHZhbHVlIG9mIHRoZSBHV1IgbW9kZWwgaW5kaWNhdGVzIHRoYXQgaXQgZG9lcyBhIGJldHRlciBqb2Igb2YgZXhwbGFpbmluZyB0aGUgdmFyaWFuY2UgaW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBcKFx0ZXh0e0xOTUVESFZBTH1cKSBjb21wYXJlZCB0byB0aGUgT0xTIG1vZGVsLiBUaGlzIGltcHJvdmVtZW50IHN1Z2dlc3RzIHRoYXQgdGhlIHNwYXRpYWwgdmFyaWFiaWxpdHkgY2FwdHVyZWQgYnkgdGhlIEdXUiBtb2RlbCBwcm92aWRlcyBhIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgcHJlZGljdG9ycyBhbmQgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgYXMgR1dSIGNhbiBhY2NvdW50IGZvciBzcGF0aWFsIGhldGVyb2dlbmVpdHkgdGhhdCBPTFMgY2Fubm90LgoKQmFzZWQgb24gdGhlIEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEFJQykgdmFsdWVzLCB0aGUgR1dSIG1vZGVsLCB3aXRoIGFuIEFJQyBvZiAzMDksIGRlbW9uc3RyYXRlcyB0aGUgYmVzdCBmaXQgYW1vbmcgdGhlIG1vZGVscyBjb21wYXJlZC4gVGhlIFNwYXRpYWwgTGFnIG1vZGVsIGhhcyBhIGhpZ2hlciBBSUMgb2YgNTI1LCBmb2xsb3dlZCBieSB0aGUgU3BhdGlhbCBFcnJvciBtb2RlbCBhdCA3NTksIGFuZCB0aGUgT0xTIHJlZ3Jlc3Npb24gbW9kZWwgYXQgMTQzNS4gU2luY2UgYSBsb3dlciBBSUMgaW5kaWNhdGVzIGEgYmV0dGVyIGZpdCwgdGhlIEdXUiBtb2RlbCBhcHBlYXJzIHRvIGJlIHRoZSBtb3N0IGVmZmVjdGl2ZSBpbiBleHBsYWluaW5nIHRoZSB2YXJpYW5jZSBpbiB0aGUgZGF0YS4gVGhpcyBzdWdnZXN0cyB0aGF0IEdXUiwgd2hpY2ggYWNjb3VudHMgZm9yIHNwYXRpYWwgaGV0ZXJvZ2VuZWl0eSBieSBhbGxvd2luZyBtb2RlbCBjb2VmZmljaWVudHMgdG8gdmFyeSBhY3Jvc3MgbG9jYXRpb25zLCBwcm92aWRlcyBhIG1vcmUgYWNjdXJhdGUgYW5kIHJvYnVzdCBmaXQgZm9yIHRoaXMgZGF0YXNldCB0aGFuIHRoZSBvdGhlciBtb2RlbHMuCgoKYGBge3IgcHJlc2VudCBnd3IgcmVzdWx0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ3dybW9kZWwKYGBgCgpUaGUgY2hvcm9wbGV0aCBtYXAgb2YgbG9jYWwgXCggUl4yIFwpIHZhbHVlcyBmcm9tIHRoZSBHV1IgbW9kZWwgaWxsdXN0cmF0ZXMgaG93IHRoZSBtb2RlbCBleHBsYWlucyB2YXJpYXRpb25zIGluIGxvZ2dlZCBtZWRpYW4gaG91c2UgdmFsdWVzIGFjcm9zcyB0aGUgY2l0eS4gRGFya2VyLWNvbG9yZWQgYXJlYXMsIHN1Y2ggYXMgdGhlIG5vcnRod2VzdGVybiwgcGFydHMgb2YgdGhlIG5vcnRoZWFzdGVybiwgYW5kIGZhciB3ZXN0ZXJuIHJlZ2lvbnMsIGluZGljYXRlIGEgc3Ryb25nZXIgbW9kZWwgZml0LCB3aGVyZSB0aGUgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwgZXhwbGFpbiBhIGxhcmdlciBwcm9wb3J0aW9uIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiBob3VzZSB2YWx1ZXMuIEluIGNvbnRyYXN0LCBsaWdodGVyLWNvbG9yZWQgYXJlYXMsIHBhcnRpY3VsYXJseSBpbiB0aGUgbm9ydGhlcm4gYW5kIHdlc3Rlcm4gcGFydHMgb2YgdGhlIGNpdHksIHNob3cgYSB3ZWFrZXIgbW9kZWwgZml0LCBzdWdnZXN0aW5nIHRoYXQgdGhlIHByZWRpY3RvcnMgYXJlIGxlc3MgZWZmZWN0aXZlIGluIGNhcHR1cmluZyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlc2UgcmVnaW9ucy4gCgpgYGB7ciBsb2NhbCBSLXNxdWFyZXMgY2hvcm9wbGV0aCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmd3cnJlc3VsdHM8LWFzLmRhdGEuZnJhbWUoZ3dybW9kZWwkU0RGKQpyZWdEYXRhc2hwcyRsb2NhbFIyPC1nd3JyZXN1bHRzJGxvY2FsUjIKcmVnRGF0YXNocHNfc2YgPC0gc3RfYXNfc2YocmVnRGF0YXNocHMpCmdncGxvdChkYXRhID0gcmVnRGF0YXNocHNfc2YpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gbG9jYWxSMiksIGNvbG9yID0gTkEpICsgIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiNGQUY5RjYiLCAiI2M0NDUzNiIpLCAKICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxvY2FsIFItU3F1YXJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gInRyYW5zcGFyZW50IikrCiAgbGFicyh0aXRsZSA9ICJMb2NhbCBSLVNxdWFyZWQgZnJvbSBHV1IiLCB4ID0gIiIsIHkgPSAiIikgKyAKICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIHNpemUgPSAwLjgpKQoKYGBgCgpUaGUgYW5hbHlzaXMgaW5kaWNhdGVzIHRoYXQgdGhlIEdXUiBtb2RlbCBoYXMgc3VjY2Vzc2Z1bGx5IHJlZHVjZWQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlc2lkdWFscyBjb21wYXJlZCB0byB0aGUgT0xTIG1vZGVsLiBJbiB0aGUgZGlzdHJpYnV0aW9uIG9mIE1vcmFu4oCZcyBJIHZhbHVlcyBmb3IgR1dSIHJlc2lkdWFscywgdGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIGlzIGNsb3NlIHRvIHplcm8sIHN1Z2dlc3RpbmcgbWluaW1hbCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBhbmQgYWxpZ25pbmcgd2l0aCB0aGUgYXNzdW1wdGlvbiBvZiB1bmNvcnJlbGF0ZWQgcmVzaWR1YWxzLiBJbiBjb250cmFzdCwgdGhlIE1vcmFu4oCZcyBJIGZvciB0aGUgT0xTIHJlc2lkdWFscyBpcyBib3RoIHBvc2l0aXZlIGFuZCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBpbmRpY2F0aW5nIGEgc3Ryb25nZXIgZGVncmVlIG9mIHNwYXRpYWwgZGVwZW5kZW5jZS4gCgpUaGUgc3BhdGlhbCBsYWcgbW9kZWwgYWxzbyByZWR1Y2VzIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMsIGFsdGhvdWdoIG5vdCBhcyBlZmZlY3RpdmVseSBhcyB0aGUgR1dSIG1vZGVsLiBUaGUgc3BhdGlhbCBlcnJvciBtb2RlbCBwZXJmb3JtcyBzaW1pbGFybHksIGJ1dCB0aGUgcmVzaWR1YWxzIGV4aGliaXQgc2xpZ2h0bHkgbW9yZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiB0aGFuIHRob3NlIG9mIHRoZSBHV1IgbW9kZWwuIE92ZXJhbGwsIHRoZXNlIHJlc3VsdHMgc3VnZ2VzdCB0aGF0IHRoZSBHV1IgbW9kZWwgcHJvdmlkZXMgdGhlIGJlc3QgZml0IGluIHRlcm1zIG9mIG1pbmltaXppbmcgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIGNhcHR1cmluZyBsb2NhbCBzcGF0aWFsIHZhcmlhdGlvbnMgbW9yZSBwcmVjaXNlbHkgdGhhbiB0aGUgc3BhdGlhbCBsYWcgYW5kIHNwYXRpYWwgZXJyb3IgbW9kZWxzLiBUaGlzIGluZGljYXRlcyB0aGF0IEdXUiBpcyBwYXJ0aWN1bGFybHkgZWZmZWN0aXZlIGZvciBtb2RlbGluZyBzcGF0aWFsIGhldGVyb2dlbmVpdHkgaW4gdGhpcyBkYXRhc2V0LgoKYGBge3IgbW9yYW4gSSBvZiBnd3IgcmVzaWR1YWxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKR1dSX21vcmFuTWM8LW1vcmFuLm1jKGd3cnJlc3VsdHMkZ3dyLmUsIHF1ZWVubGlzdCwgOTk5LCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIikKR1dSX21vcmFuTWMKCmBgYAoKVGhlIE1vcmFuJ3MgSSBzY2F0dGVyIHBsb3QgZm9yIHRoZSBHV1IgcmVzaWR1YWxzIHNob3dzIG1pbmltYWwgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIGFzIGluZGljYXRlZCBieSB0aGUgbmVhcmx5IGhvcml6b250YWwgdHJlbmQgb2YgdGhlIGxpbmUsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgR1dSIG1vZGVsIGhhcyBzdWNjZXNzZnVsbHkgYWRkcmVzc2VkIG11Y2ggb2YgdGhlIHNwYXRpYWwgZGVwZW5kZW5jeSBwcmVzZW50IGluIHRoZSBkYXRhLiBUaGlzIGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgZWFybGllciBoaXN0b2dyYW0gcmVzdWx0cywgd2hlcmUgdGhlIE1vcmFuJ3MgSSB2YWx1ZSBmb3IgR1dSIHJlc2lkdWFscyB3YXMgY2xvc2UgdG8gemVybywgZnVydGhlciBhZmZpcm1pbmcgdGhhdCB0aGUgbW9kZWwgZWZmZWN0aXZlbHkgY2FwdHVyZXMgbG9jYWwgc3BhdGlhbCB2YXJpYXRpb25zIGluIGxvZ2dlZCBtZWRpYW4gaG91c2UgdmFsdWVzLiAKCmBgYHtyIG1vcmFuIEkgb2YgZ3dyIHJlc2lkdWFscyBoaXN0b2dyYW0gYW5kIHNjYXR0ZXJwbG90LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbHQ3IDwtIGdncGxvdChkYXRhLmZyYW1lKHJlcyA9IGd3cnJlc3VsdHMkZ3dyLmUpLCBhZXMoeCA9IHJlcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsID0gIiMyODNkM2IiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID1HV1JfbW9yYW5NYyRzdGF0aXN0aWMsIGNvbG9yID0gIiNjNDQ1MzYiLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiT2JzZXJ2ZWQgYW5kIFBlcm11dGVkIE1vcmFuJ3MgSSBvZiBHV1IgUmVzaWR1YWxzIiwKICAgICAgIHN1YnRpdGxlID0gIk9ic2VydmVkIE1vcmFuJ3MgSSBpbiBSZWQiLAogICAgICAgeCA9ICJNb3JhbidzIEkiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKCnBsdDggPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIHJlc2lkdWFscyA9IGd3cnJlc3VsdHMkZ3dyLmUsCiAgc3BhdGlhbF9sYWcgPSBsYWcubGlzdHcocXVlZW5saXN0LCBnd3JyZXN1bHRzJGd3ci5lKQopLCBhZXMoeCA9IHJlc2lkdWFscywgeSA9IHNwYXRpYWxfbGFnKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzI4M2QzYiIsIGFscGhhID0gMC45LCBzaXplID0gMC42KSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICIjYzQ0NTM2Iiwgc2UgPSBGQUxTRSkgKyAKICBsYWJzKHRpdGxlID0gIk1vcmFuJ3MgSSBTY2F0dGVyIFBsb3QgZm9yIEdXUiBSZXNpZHVhbHMiLAogICAgICAgeCA9ICJMb2dnZWQgTWVkaWFuIEhvdXNlIFZhbHVlIiwKICAgICAgIHkgPSAiU3BhdGlhbCBMYWcgb2YgTE5NRURIVkFMIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQoKcGx0NyArIHBsdDgKYGBgCgpMb29raW5nIGF0IGVhY2ggcHJlZGljdG9ycyBpbiBkZXRhaWwsIHRoZSB2YWNhbmN5IHJhdGUgZ2VuZXJhbGx5IGhhcyBhIG5lZ2F0aXZlIGltcGFjdCBvbiBob3VzaW5nIHZhbHVlcywgd2l0aCBzaWduaWZpY2FudCBuZWdhdGl2ZSBlZmZlY3RzIG9ic2VydmVkIGluIENlbnRlciBDaXR5LCBub3J0aHdlc3Rlcm4gYXJlYXMsIHBhcnRzIG9mIHRoZSBub3J0aGVhc3Rlcm4gcmVnaW9uLCBhbmQgdGhlIHdlc3Rlcm4gcGFydCBvZiB0aGUgY2l0eS4gSG93ZXZlciwgdGhlcmUgaXMgYSBsb2NhbGl6ZWQgYXJlYSBpbiBzb3V0aGVybiBDZW50ZXIgQ2l0eSB3aGVyZSB2YWNhbmN5IHJhdGVzIHVuZXhwZWN0ZWRseSBoYXZlIGEgcG9zaXRpdmUgaW1wYWN0IG9uIGhvdXNpbmcgdmFsdWVzLgoKU2luZ2xlLWZhbWlseSBob3VzaW5nLCBpbiBnZW5lcmFsLCBwb3NpdGl2ZWx5IGltcGFjdHMgaG91c2luZyB2YWx1ZXMsIHBhcnRpY3VsYXJseSBpbiB0aGUgZmFyIG5vcnRoZWFzdCBhbmQgZmFyIG5vcnRod2VzdCBhcmVhcywgd2hlcmUgdGhpcyBlZmZlY3QgaXMgbW9yZSBwcm9ub3VuY2VkLiBDb252ZXJzZWx5LCBpbiBzb21lIHBhcnRzIG9mIHRoZSBjaXR54oCUc3VjaCBhcyBlYXN0ZXJuIFBoaWxhZGVscGhpYSwgcGFydHMgb2YgdGhlIHdlc3QsIGFuZCBzZWN0aW9ucyBvZiB0aGUgc291dGjigJR0aGUgaW1wYWN0IG9mIHNpbmdsZS1mYW1pbHkgaG91c2luZyBpcyBuZWdhdGl2ZSBhbmQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4KClRoZSBwZXJjZW50YWdlIG9mIHJlc2lkZW50cyB3aXRoIGEgYmFjaGVsb3LigJlzIGRlZ3JlZSBnZW5lcmFsbHkgaGFzIGEgcG9zaXRpdmUgaW1wYWN0IG9uIGhvdXNpbmcgdmFsdWVzLCB3aXRoIG5vIGFyZWFzIHNob3dpbmcgYSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgYWNyb3NzIHRoZSBjaXR5LiBUaGlzIHBvc2l0aXZlIGluZmx1ZW5jZSBpcyBlc3BlY2lhbGx5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgaW4gdGhlIG5vcnRoZXJuIGFuZCBub3J0aGVhc3Rlcm4gcGFydHMgb2YgdGhlIGNpdHkuCgpGaW5hbGx5LCB0aGUgcG92ZXJ0eSByYXRlIGdlbmVyYWxseSBoYXMgYSBuZWdhdGl2ZSBlZmZlY3Qgb24gaG91c2luZyB2YWx1ZXMuIFRoaXMgZWZmZWN0IGlzIG1vcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBpbiB0aGUgc291dGhlcm4sIGVhc3Rlcm4sIGFuZCBub3J0aHdlc3Rlcm4gcGFydHMgb2YgdGhlIGNpdHkuIAoKT3ZlcmFsbCwgdGhlc2Ugc3BhdGlhbCB2YXJpYXRpb25zIGhpZ2hsaWdodCBob3cgZGlmZmVyZW50IGZhY3RvcnMgYWZmZWN0IGhvdXNpbmcgdmFsdWVzIHVuaXF1ZWx5IGFjcm9zcyBQaGlsYWRlbHBoaWEsIGVtcGhhc2l6aW5nIHRoZSBpbXBvcnRhbmNlIG9mIGxvY2FsaXplZCBhbmFseXNpcyBpbiB1bmRlcnN0YW5kaW5nIHByb3BlcnR5IGR5bmFtaWNzLgoKYGBge3IgcmF0aW8gb2YgY29lZmZpY2llbnRzIHRvIHN0YW5kYXJkIGVycm9yLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKcmVnRGF0YXNocHNfc2YkY29lZlBDVFZBQ0FOVHN0PC1nd3JyZXN1bHRzJFBDVFZBQ0FOVC9nd3JyZXN1bHRzJFBDVFZBQ0FOVF9zZQpyZWdEYXRhc2hwc19zZiRjb2VmUENUU0lOR0xFU3N0PC1nd3JyZXN1bHRzJFBDVFNJTkdMRVMvZ3dycmVzdWx0cyRQQ1RTSU5HTEVTX3NlCnJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RCQUNITU9Sc3Q8LWd3cnJlc3VsdHMkUENUQkFDSE1PUi9nd3JyZXN1bHRzJFBDVEJBQ0hNT1Jfc2UKcmVnRGF0YXNocHNfc2YkY29lZkxOTkJFTFBPVnN0PC1nd3JyZXN1bHRzJExOTkJFTFBPVi9nd3JyZXN1bHRzJExOTkJFTFBPVl9zZQoKYGBgCgoKYGBge3IgcmF0aW8gb2YgY29lZmZpY2llbnRzIHRvIHN0YW5kYXJkIGVycm9yIHBsb3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KCnJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RWQUNBTlRzdF9jYXQgPC0gY3V0KHJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RWQUNBTlRzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygtSW5mLCAtMiwgMCwgMiwgSW5mKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiPCAtMiIsICItMiB0byAwIiwgIjAgdG8gMiIsICI+IDIiKSkKcmVnRGF0YXNocHNfc2YkY29lZlBDVFNJTkdMRVNzdF9jYXQgPC0gY3V0KHJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RTSU5HTEVTc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgLTIsIDAsIDIsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjwgLTIiLCAiLTIgdG8gMCIsICIwIHRvIDIiLCAiPiAyIikpCgpyZWdEYXRhc2hwc19zZiRjb2VmUENUQkFDSE1PUnN0X2NhdCA8LSBjdXQocmVnRGF0YXNocHNfc2YkY29lZlBDVEJBQ0hNT1JzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIC0yLCAwLCAyLCBJbmYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCI8IC0yIiwgIi0yIHRvIDAiLCAiMCB0byAyIiwgIj4gMiIpKQoKcmVnRGF0YXNocHNfc2YkY29lZkxOTkJFTFBPVnN0X2NhdCA8LSBjdXQocmVnRGF0YXNocHNfc2YkY29lZkxOTkJFTFBPVnN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgLTIsIDAsIDIsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjwgLTIiLCAiLTIgdG8gMCIsICIwIHRvIDIiLCAiPiAyIikpCgoKcDEgPC0gZ2dwbG90KHJlZ0RhdGFzaHBzX3NmKSArCiAgICBnZW9tX3NmKGFlcyhmaWxsID0gY29lZlBDVFZBQ0FOVHN0X2NhdCksIGNvbG9yID0gTkEpICsgIAogICAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoIiNjNDQ1MzYiLCAiI2YxYjFhNiIsICIjOGZhN2E1IiwgIiMyODNkM2IiKSwgCiAgICAgIG5hbWUgPSAiUmF0aW8gQ2F0ZWdvcnkiICAKICAgICkgKwogICBsYWJzKHRpdGxlID0gIlBDVFZBQ0FOVCBDb2VmZmljaWVudCB0byBTdGFuZGFyZCBFcnJvciIsCiAgICAgICB4ID0gIiIsIHkgPSAiIikgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGwgPSBOQSwgc2l6ZSA9IDAuOCkpCgpwMiA8LSBnZ3Bsb3QocmVnRGF0YXNocHNfc2YpICsKICAgIGdlb21fc2YoYWVzKGZpbGwgPSBjb2VmUENUU0lOR0xFU3N0X2NhdCksIGNvbG9yID0gTkEpICsgIAogICAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoIiNjNDQ1MzYiLCAiI2YxYjFhNiIsICIjOGZhN2E1IiwgIiMyODNkM2IiKSwgCiAgICAgIG5hbWUgPSAiUmF0aW8gQ2F0ZWdvcnkiICAKICAgICkgKwogICBsYWJzKHRpdGxlID0gIlBDVFNJTkdMRVMgQ29lZmZpY2llbnQgdG8gU3RhbmRhcmQgRXJyb3IiLAogICAgICAgeCA9ICIiLCB5ID0gIiIpICsKICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIHNpemUgPSAwLjgpKQoKCnAzIDwtIGdncGxvdChyZWdEYXRhc2hwc19zZikgKwogICAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvZWZQQ1RCQUNITU9Sc3RfY2F0KSwgY29sb3IgPSBOQSkgKyAgCiAgICBzY2FsZV9maWxsX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygiI2M0NDUzNiIsICIjZjFiMWE2IiwgIiM4ZmE3YTUiLCAiIzI4M2QzYiIpLCAKICAgICAgbmFtZSA9ICJSYXRpbyBDYXRlZ29yeSIgIAogICAgKSArCiAgIGxhYnModGl0bGUgPSAiUENUQkFDSE1PUiBDb2VmZmljaWVudCB0byBTdGFuZGFyZCBFcnJvciIsCiAgICAgICB4ID0gIiIsIHkgPSAiIikgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGwgPSBOQSwgc2l6ZSA9IDAuOCkpCgpwNCA8LSBnZ3Bsb3QocmVnRGF0YXNocHNfc2YpICsKICAgIGdlb21fc2YoYWVzKGZpbGwgPSBjb2VmTE5OQkVMUE9Wc3RfY2F0KSwgY29sb3IgPSBOQSkgKyAgCiAgICBzY2FsZV9maWxsX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygiI2M0NDUzNiIsICIjZjFiMWE2IiwgIiM4ZmE3YTUiLCAiIzI4M2QzYiIpLCAKICAgICAgbmFtZSA9ICJSYXRpbyBDYXRlZ29yeSIgIAogICAgKSArCiAgIGxhYnModGl0bGUgPSAiTE5OQkVMUE9WIENvZWZmaWNpZW50IHRvIFN0YW5kYXJkIEVycm9yIiwKICAgICAgIHggPSAiIiwgeSA9ICIiKSArCiAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbCA9IE5BLCBzaXplID0gMC44KSkKCnAxICsgcDIgKyBwMyArIHA0ICsgCiAgcGxvdF9sYXlvdXQobmNvbCA9IDIpCmBgYAoKIyBEaXNjdXNzaW9uCgpJbiB0aGlzIHJlcG9ydCwgd2UgY29uZHVjdGVkIGEgY29tcGFyYXRpdmUgYW5hbHlzaXMgb2YgZm91ciByZWdyZXNzaW9uIG1ldGhvZHPigJRPcmRpbmFyeSBMZWFzdCBTcXVhcmVzIChPTFMpLCBTcGF0aWFsIExhZywgU3BhdGlhbCBFcnJvciwgYW5kIEdlb2dyYXBoaWNhbGx5IFdlaWdodGVkIFJlZ3Jlc3Npb24gKEdXUinigJR0byBldmFsdWF0ZSB0aGVpciBlZmZlY3RpdmVuZXNzIGluIGV4cGxhaW5pbmcgdGhlIHZhcmlhbmNlIGluIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIFwoXHRleHR7TE5NRURIVkFMfVwpLiBPdXIgZmluZGluZ3MgaW5kaWNhdGUgdGhhdCB0aGUgR1dSIG1vZGVsIGV4aGliaXRlZCB0aGUgaGlnaGVzdCBleHBsYW5hdG9yeSBwb3dlciwgd2l0aCBhIHF1YXNpLWdsb2JhbCBcKFJeMlwpIG9mIDAuODQsIGNvbXBhcmVkIHRvIHRoZSBPTFMgXChSXjJcKSBvZiAwLjY2Miwgc3VnZ2VzdGluZyB0aGF0IEdXUiBpcyBiZXR0ZXIgc3VpdGVkIHRvIGNhcHR1cmUgbG9jYWwgdmFyaWF0aW9ucyBpbiB0aGUgZGF0YS4KClRoZSBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpIGZ1cnRoZXIgc3VwcG9ydHMgdGhlIHN1aXRhYmlsaXR5IG9mIEdXUiwgd2hpY2ggYWNoaWV2ZWQgYW4gQUlDIG9mIDMwOSwgaW4gY29udHJhc3QgdG8gdGhlIE9MUyBBSUMgb2YgMTQzNSwgdGhlIFNwYXRpYWwgTGFnIEFJQyBvZiA1MjUsIGFuZCB0aGUgU3BhdGlhbCBFcnJvciBBSUMgb2YgNzU5LiBOZXZlcnRoZWxlc3MsIHRoZSBsb3dlciBBSUMgdmFsdWVzIGluIHNwYXRpYWwgbGFnIGFuZCBzcGF0aWFsIGVycm9yIHJlZ3Jlc3Npb24gc3RpbGwgaW5kaWNhdGUgdGhhdCBib3RoIG1vZGVscyBwcm92aWRlIGFyZSBtdWNoIGJldHRlciBmaXQgdGhhbiB0aGUgT0xTIG1vZGVsLCBlc3BlY2lhbGx5IHRoZSBzcGF0aWFsIGxhZyBtb2RlbC4gQW5vdGhlciBvYnNlcnZhdGlvbiBpcyB0aGUgcmVkdWN0aW9uIGluIHRoZSBjb2VmZmljaWVudCBtYWduaXR1ZGVzIGZvciB0aGUgcHJlZGljdG9ycyBpbiB0aGUgc3BhdGlhbCBsYWcgYW5kIHNwYXRpYWwgZXJyb3IgbW9kZWxzIGNvbXBhcmVkIHRvIE9MUywgc3VnZ2VzdGluZyB0aGF0IHRoZXkgcHJvdmlkZSBtb3JlIGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZXMgb2YgdGhlIHByZWRpY3RvcnMnIGVmZmVjdHMgb24gbWVkaWFuIGhvbWUgdmFsdWVzIGZvciBhY2NvdW50aW5nIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLiBZZXQsIG92ZXJhbGwsIG91ciBhbmFseXNpcyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgR1dSIG1ldGhvZCBpcyB0aGUgbW9zdCBlZmZlY3RpdmUgZm9yIHRoaXMgZGF0YXNldC4gCgpXaGlsZSBHV1Igb2ZmZXJzIHNldmVyYWwgYWR2YW50YWdlcywgc3VjaCBhcyBjYXB0dXJpbmcgc3BhdGlhbCBoZXRlcm9nZW5laXR5IGFuZCBwcm92aWRpbmcgbG9jYWxpemVkIGluc2lnaHRzLCBpdCBhbHNvIGhhcyBsaW1pdGF0aW9ucywgd2hpY2ggaXMgd2h5IGEgbG90IG9mIHNwYXRpYWwgc3RhdGlzdGljaWFucyB1c2UgaXQgb25seSBmb3IgZGF0YSBleHBsb3JhdGlvbiByYXRoZXIgdGhhbiBmb3IgbW9kZWxpbmcuIE1vc3Qgbm90YWJseSwgYSBsb3Qgb2YgYXNzdW1wdGlvbnMgd2UgaGF2ZSBpbiBPTFMgc3RpbGwgaG9sZCBpbiBHV1IsIHN1Y2ggYXMgbGluZWFyaXR5LCBob21vc2NlZGFzdGljaXR5LCBhbmQgbm9ybWFsaXR5IG9mIGVycm9ycy4gQXMgYW4gZXhhbXBsZSwgZnJvbSBvdXIgcHJldmlvdXMgYXNzaWdubWVudCwgd2Uga25vdyB0aGF0IHRoZXJlJ3MgbXVsdGljb2xsaW5lYXJpdHkgYmV0d2VlbiBwcmVkaWN0b3JzIC0gaGlnaGVyIGVkdWNhdGlvbiBhdHRhaW5tZW50IGlzIGNsZWFybHkgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIHBvdmVydHkgbGV2ZWwuIEFzIHN1Y2gsIG91ciBjdXJyZW50IEdXUiBtb2RlbCBjbGVhcmx5IGRvZXMgbm90IGFjY291bnQgZm9yIHRoYXQuIFdlIGFsc28ga25vdyB0aGF0IHNvbWUgb2Ygb3VyIHByZWRpY3RvciB2YXJpYWJsZXMsIHN1Y2ggYXMgXChcdGV4dHtQQ1RTSU5HTEVTfVwpIGFuZCBcKFx0ZXh0e1BDVEJBQ0hNT1J9XCkgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCwgd2hpY2ggdmlvbGF0ZXMgdGhlIGFzc3VtcHRpb24uIAoKT3RoZXIgdGhhbiB0aGF0LCBHV1IgcmVxdWlyZXMgYXQgbGVhc3QgMzAwIG9ic2VydmF0aW9ucyBhbmQgdXNlcidzIGNob2ljZSBvZiBiYW5kd2lkdGggY2FuIHNpZ25pZmljYW50bHkgYWZmZWN0IHJlc3VsdHMuIEluIG91ciBleGFtcGxlIHdlIGhhdmUgd2F5IG1vcmUgdGhhbiAzMDAgb2JzZXJ2YXRpb25zIGFuZCBSIGF1dG9tYXRpY2FsbHkgcGlja2VkIHRoZSBiYW5kd2lkdGhzIGZvciB1cywgc3RpbGwgd2Ugc2hvdWxkIGJlIGNhdXRpb3VzIGFib3V0IHRoZSByZXN1bHRzLgoKV2UgYWxzbyBuZWVkIHRvIGJlIGNhcmVmdWwgYWJvdXQgdGhlIHRoZSB1c2Ugb2YgdGVybSBiZXR3ZWVuICoqc3BhdGlhbGx5IGxhZ2dlZCByZXNpZHVhbHMqKiBhbmQgKipzcGF0aWFsIGxhZyBtb2RlbCByZXNpZHVhbHMqKi4gVGhlIGZvcm1lciB0ZXJtLCAqKnNwYXRpYWxseSBsYWdnZWQgcmVzaWR1YWxzKiosIHJlZmVycyB0byBhIHNlcmllcyBvZiByZXNpZHVhbHMgdGhhdCB0YWtlIGludG8gYWNjb3VudCB0aGUgaW5mbHVlbmNlIG9mIG5lYXJieSBvYnNlcnZhdGlvbnMgdGhyb3VnaCBhIHdlaWdodGluZyBzY2hlbWUuIFRoZSBsYXR0ZXIgdGVybSwgKipzcGF0aWFsIGxhZyBtb2RlbCByZXNpZHVhbHMqKiByZWZlcnMgdG8gdGhlIGVycm9yIHRlcm1zIGZyb20gdGhlIHJlc3VsdCBvZiBhIG1vZGVsIHRoYXQgaW5jb3Jwb3JhdGVzIGEgc3BhdGlhbCBsYWcgdGVybSAod2hpY2ggaXMgdGhlIHZhbHVlcyBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGZyb20gbmVpZ2hib3Jpbmcgb2JzZXJ2YXRpb25zKS4gCgpBbmQgbGFzdGx5LCB3ZSB3b3VsZCBsaWtlIHRvIGhpZ2hsaWdodCBzb21lIGxpbWl0YXRpb25zIG9mIHVzaW5nIEFyY0dJUyBmb3IgR1dSLiBUaGUgbWFqb3IgaXNzdWVzIGlzIHRoYXQgQXJjR0lTIGRvZXMgbm90IGFsd2F5cyBhbGxvdyBmb3IgdGhlIHNhbWUgbGV2ZWwgb2YgZmxleGliaWxpdHkgaW4gc2VsZWN0aW5nIGJhbmR3aWR0aCBtZXRob2RzIG9yIGtlcm5lbCBmdW5jdGlvbnMgYXMgUiwgYW5kIGl0IGhhcyBhIHZlcnkgZGlmZmVyZW50IGFuZCB2ZXJ5IGNvbmZ1c2luZyB3YXkgb2Ygb3B0aW1pemluZyBiYW5kd2lkdGguIEluIGFkZGl0aW9uLCBBcmNHSVMgUHJvIGRvZXMgbm90IGdpdmUgQUlDLCBqdXN0IEFJQ2MsIHdoaWNoIG1ha2VzIGl0IGRpZmZpY3VsdCB0byBjb21wYXJlIEdXUiBvdXRwdXQgdG8gb3RoZXIgbW9kZWxzLiBNb3JlIGltcG9ydGFudGx5LCBpbiB0aGUgY3VycmVudCBhbmQgZWFybGllciB2ZXJzaW9ucyBvZiBBcmNHSVMgUHJvLCBzb21lIGxvY2FsIFItc3F1YXJlcyBhcmUgbmVnYXRpdmUsIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSBpbiBhIHJlZ3Jlc3Npb24gbW9kZWwuIFRoZXJlZm9yZSwgd2UgcmVjb21tZW5kIHVzaW5nIFIgZm9yIEdXUiBhbmFseXNpcyB0byBhdm9pZCB0aGVzZSBsaW1pdGF0aW9ucyBhbmQgdG8gaGF2ZSBtb3JlIGNvbnRyb2wgb3ZlciB0aGUgbW9kZWwgc2VsZWN0aW9uIHByb2Nlc3MuCgoKCgoKIyBSZWZlcmVuY2UKCkFuc2VsaW4sIEwuICgxOTg4KS4gU3BhdGlhbCBlY29ub21ldHJpY3M6IE1ldGhvZHMgYW5kIG1vZGVscy4gS2x1d2VyIEFjYWRlbWljIFB1Ymxpc2hlcnMuCgpBdGtpbnNvbiwgUi4gKDIwMDQpLiBUaGUgZXZpZGVuY2Ugb24gdGhlIGltcGFjdCBvZiBnZW50cmlmaWNhdGlvbjogTmV3IGxlc3NvbnMgZm9yIHRoZSB1cmJhbiByZW5haXNzYW5jZT8gRXVyb3BlYW4gSm91cm5hbCBvZiBIb3VzaW5nIFBvbGljeSwgNCgxKSwgMTA34oCTMTMxLiBodHRwczovL2RvaS5vcmcvMTAuMTA4MC8xNDYxNjcxMDQyMDAwMjE1NDc5CgpCcnVuc2RvbiwgQy4sIEZvdGhlcmluZ2hhbSwgQS4gUy4sICYgQ2hhcmx0b24sIE0uIEUuICgxOTk2KS4gR2VvZ3JhcGhpY2FsbHkgd2VpZ2h0ZWQgcmVncmVzc2lvbjogQSBtZXRob2QgZm9yIGV4cGxvcmluZyBzcGF0aWFsIG5vbnN0YXRpb25hcml0eS4gR2VvZ3JhcGhpY2FsIEFuYWx5c2lzLCAyOCg0KSwgMjgx4oCTMjk4LiBodHRwczovL2RvaS5vcmcvMTAuMTExMS9qLjE1MzgtNDYzMi4xOTk2LnRiMDA5MzYueAoKRnJlZW1hbiwgTC4sICYgQnJhY29uaSwgRi4gKDIwMDQpLiBHZW50cmlmaWNhdGlvbiBhbmQgZGlzcGxhY2VtZW50LiBKb3VybmFsIG9mIHRoZSBBbWVyaWNhbiBQbGFubmluZyBBc3NvY2lhdGlvbiwgNzAoMSksIDM54oCTNTIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzAxOTQ0MzYwNDA4OTc2MzM3CgpHYWxzdGVyLCBHLiBDLiAoMjAwOCkuIFF1YW50aWZ5aW5nIHRoZSBlZmZlY3Qgb2YgbmVpZ2hib3Job29kIGxhbmQgdXNlIGFuZCB6b25pbmcgb24gaG91c2luZyBwcmljZXMuIFJlZ2lvbmFsIFNjaWVuY2UgYW5kIFVyYmFuIEVjb25vbWljcywgMzgoMyksIDI5MeKAkzMwNS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5yZWdzY2l1cmJlY28uMjAwOC4wMy4wMDMKCkdsYWVzZXIsIEUuIEwuLCAmIEd5b3Vya28sIEouICgyMDE4KS4gUmV0aGlua2luZyBmZWRlcmFsIGhvdXNpbmcgcG9saWN5OiBIb3cgdG8gbWFrZSBob3VzaW5nIHBsZW50aWZ1bCBhbmQgYWZmb3JkYWJsZS4gQW1lcmljYW4gRW50ZXJwcmlzZSBJbnN0aXR1dGUuCgpMZWVzLCBMLiAoMjAwOCkuIEdlbnRyaWZpY2F0aW9uIGFuZCBzb2NpYWwgbWl4aW5nOiBUb3dhcmRzIGFuIGluY2x1c2l2ZSB1cmJhbiByZW5haXNzYW5jZT8gVXJiYW4gU3R1ZGllcywgNDUoMTIpLCAyNDQ54oCTMjQ3MC4gaHR0cHM6Ly9kb2kub3JnLzEwLjExNzcvMDA0MjA5ODAwODA5NzA5OQoKTGVTYWdlLCBKLiwgJiBQYWNlLCBSLiBLLiAoMjAwOSkuIEludHJvZHVjdGlvbiB0byBzcGF0aWFsIGVjb25vbWV0cmljcy4gQ1JDIFByZXNzLgoKTWFsbGFjaCwgQS4gKDIwMTgpLiBUaGUgZGl2aWRlZCBjaXR5OiBQb3ZlcnR5IGFuZCBwcm9zcGVyaXR5IGluIHVyYmFuIEFtZXJpY2EuIElzbGFuZCBQcmVzcy4gaHR0cHM6Ly9kb2kub3JnLzEwLjU4MjIvOTc4LTEtNjEwOTEtNzgxLTAKClRvYmxlciwgVy4gKDE5NzApLiBBIGNvbXB1dGVyIG1vdmllIHNpbXVsYXRpbmcgdXJiYW4gZ3Jvd3RoIGluIHRoZSBEZXRyb2l0IHJlZ2lvbi4gRWNvbm9taWMgR2VvZ3JhcGh5LCA0NiwgMjM04oCTMjQwLiBodHRwczovL2RvaS5vcmcvMTAuMjMwNy8xNDMxNDEK